View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.master;
21  
22  import java.io.IOException;
23  import java.util.List;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.Coprocessor;
29  import org.apache.hadoop.hbase.HColumnDescriptor;
30  import org.apache.hadoop.hbase.HRegionInfo;
31  import org.apache.hadoop.hbase.HTableDescriptor;
32  import org.apache.hadoop.hbase.NamespaceDescriptor;
33  import org.apache.hadoop.hbase.ServerName;
34  import org.apache.hadoop.hbase.TableName;
35  import org.apache.hadoop.hbase.classification.InterfaceAudience;
36  import org.apache.hadoop.hbase.coprocessor.*;
37  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
38  
39  import java.io.IOException;
40  import java.util.List;
41  
42  /**
43   * Provides the coprocessor framework and environment for master oriented
44   * operations.  {@link HMaster} interacts with the loaded coprocessors
45   * through this class.
46   */
47  @InterfaceAudience.Private
48  public class MasterCoprocessorHost
49      extends CoprocessorHost<MasterCoprocessorHost.MasterEnvironment> {
50  
51    private static final Log LOG = LogFactory.getLog(MasterCoprocessorHost.class);
52  
53    /**
54     * Coprocessor environment extension providing access to master related
55     * services.
56     */
57    static class MasterEnvironment extends CoprocessorHost.Environment
58        implements MasterCoprocessorEnvironment {
59      private MasterServices masterServices;
60  
61      public MasterEnvironment(final Class<?> implClass, final Coprocessor impl,
62          final int priority, final int seq, final Configuration conf,
63          final MasterServices services) {
64        super(impl, priority, seq, conf);
65        this.masterServices = services;
66      }
67  
68      public MasterServices getMasterServices() {
69        return masterServices;
70      }
71    }
72  
73    private MasterServices masterServices;
74  
75    public MasterCoprocessorHost(final MasterServices services, final Configuration conf) {
76      super(services);
77      this.conf = conf;
78      this.masterServices = services;
79      // Log the state of coprocessor loading here; should appear only once or
80      // twice in the daemon log, depending on HBase version, because there is
81      // only one MasterCoprocessorHost instance in the master process
82      boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
83        DEFAULT_COPROCESSORS_ENABLED);
84      LOG.info("System coprocessor loading is " + (coprocessorsEnabled ? "enabled" : "disabled"));
85      loadSystemCoprocessors(conf, MASTER_COPROCESSOR_CONF_KEY);
86    }
87  
88    @Override
89    public MasterEnvironment createEnvironment(final Class<?> implClass,
90        final Coprocessor instance, final int priority, final int seq,
91        final Configuration conf) {
92      for (Class<?> c : implClass.getInterfaces()) {
93        if (CoprocessorService.class.isAssignableFrom(c)) {
94          masterServices.registerService(((CoprocessorService)instance).getService());
95        }
96      }
97      return new MasterEnvironment(implClass, instance, priority, seq, conf,
98          masterServices);
99    }
100 
101   public boolean preCreateNamespace(final NamespaceDescriptor ns) throws IOException {
102     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
103       @Override
104       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
105           throws IOException {
106         oserver.preCreateNamespace(ctx, ns);
107       }
108     });
109   }
110 
111   public void postCreateNamespace(final NamespaceDescriptor ns) throws IOException {
112     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
113       @Override
114       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
115           throws IOException {
116         oserver.postCreateNamespace(ctx, ns);
117       }
118     });
119   }
120 
121   public boolean preDeleteNamespace(final String namespaceName) throws IOException {
122     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
123       @Override
124       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
125           throws IOException {
126         oserver.preDeleteNamespace(ctx, namespaceName);
127       }
128     });
129   }
130 
131   public void postDeleteNamespace(final String namespaceName) throws IOException {
132     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
133       @Override
134       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
135           throws IOException {
136         oserver.postDeleteNamespace(ctx, namespaceName);
137       }
138     });
139   }
140 
141   public boolean preModifyNamespace(final NamespaceDescriptor ns) throws IOException {
142     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
143       @Override
144       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
145           throws IOException {
146         oserver.preModifyNamespace(ctx, ns);
147       }
148     });
149   }
150 
151   public void postModifyNamespace(final NamespaceDescriptor ns) throws IOException {
152     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
153       @Override
154       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
155           throws IOException {
156         oserver.postModifyNamespace(ctx, ns);
157       }
158     });
159   }
160 
161   public void preGetNamespaceDescriptor(final String namespaceName)
162       throws IOException {
163     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
164       @Override
165       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
166           throws IOException {
167         oserver.preGetNamespaceDescriptor(ctx, namespaceName);
168       }
169     });
170   }
171 
172   public void postGetNamespaceDescriptor(final NamespaceDescriptor ns)
173       throws IOException {
174     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
175       @Override
176       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
177           throws IOException {
178         oserver.postGetNamespaceDescriptor(ctx, ns);
179       }
180     });
181   }
182 
183   public boolean preListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
184       throws IOException {
185     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
186       @Override
187       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
188           throws IOException {
189         oserver.preListNamespaceDescriptors(ctx, descriptors);
190       }
191     });
192   }
193 
194   public void postListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
195       throws IOException {
196     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
197       @Override
198       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
199           throws IOException {
200         oserver.postListNamespaceDescriptors(ctx, descriptors);
201       }
202     });
203   }
204 
205   /* Implementation of hooks for invoking MasterObservers */
206 
207   public void preCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
208       throws IOException {
209     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
210       @Override
211       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
212           throws IOException {
213         oserver.preCreateTable(ctx, htd, regions);
214       }
215     });
216   }
217 
218   public void postCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
219       throws IOException {
220     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
221       @Override
222       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
223           throws IOException {
224         oserver.postCreateTable(ctx, htd, regions);
225       }
226     });
227   }
228 
229   public void preCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
230       throws IOException {
231     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
232       @Override
233       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
234           throws IOException {
235         oserver.preCreateTableHandler(ctx, htd, regions);
236       }
237     });
238   }
239 
240   public void postCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
241       throws IOException {
242     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
243       @Override
244       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
245           throws IOException {
246         oserver.postCreateTableHandler(ctx, htd, regions);
247       }
248     });
249   }
250 
251   public void preDeleteTable(final TableName tableName) throws IOException {
252     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
253       @Override
254       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
255           throws IOException {
256         oserver.preDeleteTable(ctx, tableName);
257       }
258     });
259   }
260 
261   public void postDeleteTable(final TableName tableName) throws IOException {
262     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
263       @Override
264       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
265           throws IOException {
266         oserver.postDeleteTable(ctx, tableName);
267       }
268     });
269   }
270 
271   public void preDeleteTableHandler(final TableName tableName) throws IOException {
272     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
273       @Override
274       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
275           throws IOException {
276         oserver.preDeleteTableHandler(ctx, tableName);
277       }
278     });
279   }
280 
281   public void postDeleteTableHandler(final TableName tableName) throws IOException {
282     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
283       @Override
284       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
285           throws IOException {
286         oserver.postDeleteTableHandler(ctx, tableName);
287       }
288     });
289   }
290 
291   public void preTruncateTable(final TableName tableName) throws IOException {
292     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
293       @Override
294       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
295           throws IOException {
296         oserver.preTruncateTable(ctx, tableName);
297       }
298     });
299   }
300 
301   public void postTruncateTable(final TableName tableName) throws IOException {
302     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
303       @Override
304       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
305           throws IOException {
306         oserver.postTruncateTable(ctx, tableName);
307       }
308     });
309   }
310 
311   public void preTruncateTableHandler(final TableName tableName) throws IOException {
312     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
313       @Override
314       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
315           throws IOException {
316         oserver.preTruncateTableHandler(ctx, tableName);
317       }
318     });
319   }
320 
321   public void postTruncateTableHandler(final TableName tableName) throws IOException {
322     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
323       @Override
324       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
325           throws IOException {
326         oserver.postTruncateTableHandler(ctx, tableName);
327       }
328     });
329   }
330 
331   public void preModifyTable(final TableName tableName, final HTableDescriptor htd)
332       throws IOException {
333     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
334       @Override
335       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
336           throws IOException {
337         oserver.preModifyTable(ctx, tableName, htd);
338       }
339     });
340   }
341 
342   public void postModifyTable(final TableName tableName, final HTableDescriptor htd)
343       throws IOException {
344     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
345       @Override
346       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
347           throws IOException {
348         oserver.postModifyTable(ctx, tableName, htd);
349       }
350     });
351   }
352 
353   public void preModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
354       throws IOException {
355     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
356       @Override
357       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
358           throws IOException {
359         oserver.preModifyTableHandler(ctx, tableName, htd);
360       }
361     });
362   }
363 
364   public void postModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
365       throws IOException {
366     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
367       @Override
368       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
369           throws IOException {
370         oserver.postModifyTableHandler(ctx, tableName, htd);
371       }
372     });
373   }
374 
375   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor column)
376       throws IOException {
377     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
378       @Override
379       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
380           throws IOException {
381         oserver.preAddColumn(ctx, tableName, column);
382       }
383     });
384   }
385 
386   public void postAddColumn(final TableName tableName, final HColumnDescriptor column)
387       throws IOException {
388     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
389       @Override
390       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
391           throws IOException {
392         oserver.postAddColumn(ctx, tableName, column);
393       }
394     });
395   }
396 
397   public boolean preAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
398       throws IOException {
399     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
400       @Override
401       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
402           throws IOException {
403         oserver.preAddColumnHandler(ctx, tableName, column);
404       }
405     });
406   }
407 
408   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
409       throws IOException {
410     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
411       @Override
412       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
413           throws IOException {
414         oserver.postAddColumnHandler(ctx, tableName, column);
415       }
416     });
417   }
418 
419   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
420       throws IOException {
421     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
422       @Override
423       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
424           throws IOException {
425         oserver.preModifyColumn(ctx, tableName, descriptor);
426       }
427     });
428   }
429 
430   public void postModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
431       throws IOException {
432     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
433       @Override
434       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
435           throws IOException {
436         oserver.postModifyColumn(ctx, tableName, descriptor);
437       }
438     });
439   }
440 
441   public boolean preModifyColumnHandler(final TableName tableName,
442       final HColumnDescriptor descriptor) throws IOException {
443     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
444       @Override
445       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
446           throws IOException {
447         oserver.preModifyColumnHandler(ctx, tableName, descriptor);
448       }
449     });
450   }
451 
452   public void postModifyColumnHandler(final TableName tableName,
453       final HColumnDescriptor descriptor) throws IOException {
454     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
455       @Override
456       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
457           throws IOException {
458         oserver.postModifyColumnHandler(ctx, tableName, descriptor);
459       }
460     });
461   }
462 
463   public boolean preDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
464     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
465       @Override
466       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
467           throws IOException {
468         oserver.preDeleteColumn(ctx, tableName, c);
469       }
470     });
471   }
472 
473   public void postDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
474     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
475       @Override
476       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
477           throws IOException {
478         oserver.postDeleteColumn(ctx, tableName, c);
479       }
480     });
481   }
482 
483   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] c)
484       throws IOException {
485     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
486       @Override
487       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
488           throws IOException {
489         oserver.preDeleteColumnHandler(ctx, tableName, c);
490       }
491     });
492   }
493 
494   public void postDeleteColumnHandler(final TableName tableName, final byte[] c)
495       throws IOException {
496     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
497       @Override
498       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
499           throws IOException {
500         oserver.postDeleteColumnHandler(ctx, tableName, c);
501       }
502     });
503   }
504 
505   public void preEnableTable(final TableName tableName) throws IOException {
506     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
507       @Override
508       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
509           throws IOException {
510         oserver.preEnableTable(ctx, tableName);
511       }
512     });
513   }
514 
515   public void postEnableTable(final TableName tableName) throws IOException {
516     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
517       @Override
518       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
519           throws IOException {
520         oserver.postEnableTable(ctx, tableName);
521       }
522     });
523   }
524 
525   public void preEnableTableHandler(final TableName tableName) throws IOException {
526     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
527       @Override
528       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
529           throws IOException {
530         oserver.preEnableTableHandler(ctx, tableName);
531       }
532     });
533   }
534 
535   public void postEnableTableHandler(final TableName tableName) throws IOException {
536     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
537       @Override
538       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
539           throws IOException {
540         oserver.postEnableTableHandler(ctx, tableName);
541       }
542     });
543   }
544 
545   public void preDisableTable(final TableName tableName) throws IOException {
546     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
547       @Override
548       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
549           throws IOException {
550         oserver.preDisableTable(ctx, tableName);
551       }
552     });
553   }
554 
555   public void postDisableTable(final TableName tableName) throws IOException {
556     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
557       @Override
558       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
559           throws IOException {
560         oserver.postDisableTable(ctx, tableName);
561       }
562     });
563   }
564 
565   public void preDisableTableHandler(final TableName tableName) throws IOException {
566     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
567       @Override
568       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
569           throws IOException {
570         oserver.preDisableTableHandler(ctx, tableName);
571       }
572     });
573   }
574 
575   public void postDisableTableHandler(final TableName tableName) throws IOException {
576     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
577       @Override
578       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
579           throws IOException {
580         oserver.postDisableTableHandler(ctx, tableName);
581       }
582     });
583   }
584 
585   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
586       final ServerName destServer) throws IOException {
587     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
588       @Override
589       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
590           throws IOException {
591         oserver.preMove(ctx, region, srcServer, destServer);
592       }
593     });
594   }
595 
596   public void postMove(final HRegionInfo region, final ServerName srcServer,
597       final ServerName destServer) throws IOException {
598     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
599       @Override
600       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
601           throws IOException {
602         oserver.postMove(ctx, region, srcServer, destServer);
603       }
604     });
605   }
606 
607   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
608     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
609       @Override
610       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
611           throws IOException {
612         oserver.preAssign(ctx, regionInfo);
613       }
614     });
615   }
616 
617   public void postAssign(final HRegionInfo regionInfo) throws IOException {
618     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
619       @Override
620       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
621           throws IOException {
622         oserver.postAssign(ctx, regionInfo);
623       }
624     });
625   }
626 
627   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
628       throws IOException {
629     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
630       @Override
631       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
632           throws IOException {
633         oserver.preUnassign(ctx, regionInfo, force);
634       }
635     });
636   }
637 
638   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
639     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
640       @Override
641       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
642           throws IOException {
643         oserver.postUnassign(ctx, regionInfo, force);
644       }
645     });
646   }
647 
648   public void preRegionOffline(final HRegionInfo regionInfo) throws IOException {
649     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
650       @Override
651       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
652           throws IOException {
653         oserver.preRegionOffline(ctx, regionInfo);
654       }
655     });
656   }
657 
658   public void postRegionOffline(final HRegionInfo regionInfo) throws IOException {
659     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
660       @Override
661       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
662           throws IOException {
663         oserver.postRegionOffline(ctx, regionInfo);
664       }
665     });
666   }
667 
668   public boolean preBalance() throws IOException {
669     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
670       @Override
671       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
672           throws IOException {
673         oserver.preBalance(ctx);
674       }
675     });
676   }
677 
678   public void postBalance(final List<RegionPlan> plans) throws IOException {
679     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
680       @Override
681       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
682           throws IOException {
683         oserver.postBalance(ctx, plans);
684       }
685     });
686   }
687 
688   public boolean preBalanceSwitch(final boolean b) throws IOException {
689     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
690         new CoprocessorOperationWithResult<Boolean>() {
691       @Override
692       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
693           throws IOException {
694         setResult(oserver.preBalanceSwitch(ctx, getResult()));
695       }
696     });
697   }
698 
699   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
700       throws IOException {
701     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
702       @Override
703       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
704           throws IOException {
705         oserver.postBalanceSwitch(ctx, oldValue, newValue);
706       }
707     });
708   }
709 
710   public void preShutdown() throws IOException {
711     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
712       @Override
713       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
714           throws IOException {
715         oserver.preShutdown(ctx);
716       }
717       @Override
718       public void postEnvCall(MasterEnvironment env) {
719         // invoke coprocessor stop method
720         shutdown(env);
721       }
722     });
723   }
724 
725   public void preStopMaster() throws IOException {
726     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
727       @Override
728       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
729           throws IOException {
730         oserver.preStopMaster(ctx);
731       }
732       @Override
733       public void postEnvCall(MasterEnvironment env) {
734         // invoke coprocessor stop method
735         shutdown(env);
736       }
737     });
738   }
739 
740   public void preMasterInitialization() throws IOException {
741     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
742       @Override
743       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
744           throws IOException {
745         oserver.preMasterInitialization(ctx);
746       }
747     });
748   }
749 
750   public void postStartMaster() throws IOException {
751     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
752       @Override
753       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
754           throws IOException {
755         oserver.postStartMaster(ctx);
756       }
757     });
758   }
759 
760   public void preSnapshot(final SnapshotDescription snapshot,
761       final HTableDescriptor hTableDescriptor) throws IOException {
762     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
763       @Override
764       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
765           throws IOException {
766         oserver.preSnapshot(ctx, snapshot, hTableDescriptor);
767       }
768     });
769   }
770 
771   public void postSnapshot(final SnapshotDescription snapshot,
772       final HTableDescriptor hTableDescriptor) throws IOException {
773     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
774       @Override
775       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
776           throws IOException {
777         oserver.postSnapshot(ctx, snapshot, hTableDescriptor);
778       }
779     });
780   }
781 
782   public void preCloneSnapshot(final SnapshotDescription snapshot,
783       final HTableDescriptor hTableDescriptor) throws IOException {
784     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
785       @Override
786       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
787           throws IOException {
788         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
789       }
790     });
791   }
792 
793   public void postCloneSnapshot(final SnapshotDescription snapshot,
794       final HTableDescriptor hTableDescriptor) throws IOException {
795     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
796       @Override
797       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
798           throws IOException {
799         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
800       }
801     });
802   }
803 
804   public void preRestoreSnapshot(final SnapshotDescription snapshot,
805       final HTableDescriptor hTableDescriptor) throws IOException {
806     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
807       @Override
808       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
809           throws IOException {
810         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
811       }
812     });
813   }
814 
815   public void postRestoreSnapshot(final SnapshotDescription snapshot,
816       final HTableDescriptor hTableDescriptor) throws IOException {
817     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
818       @Override
819       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
820           throws IOException {
821         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
822       }
823     });
824   }
825 
826   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
827     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
828       @Override
829       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
830           throws IOException {
831         oserver.preDeleteSnapshot(ctx, snapshot);
832       }
833     });
834   }
835 
836   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
837     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
838       @Override
839       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
840           throws IOException {
841         oserver.postDeleteSnapshot(ctx, snapshot);
842       }
843     });
844   }
845 
846   @Deprecated
847   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
848     final List<HTableDescriptor> descriptors) throws IOException {
849     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
850       @Override
851       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
852           throws IOException {
853         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors);
854       }
855     });
856   }
857 
858   @Deprecated
859   public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
860       throws IOException {
861     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
862       @Override
863       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
864           throws IOException {
865         oserver.postGetTableDescriptors(ctx, descriptors);
866       }
867     });
868   }
869 
870   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
871       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
872     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
873       @Override
874       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
875           throws IOException {
876         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
877       }
878     });
879   }
880 
881   public void postGetTableDescriptors(final List<TableName> tableNamesList,
882       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
883     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
884       @Override
885       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
886           throws IOException {
887         oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
888       }
889     });
890   }
891 
892   public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
893       final String regex) throws IOException {
894     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
895       @Override
896       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
897           throws IOException {
898         oserver.preGetTableNames(ctx, descriptors, regex);
899       }
900     });
901   }
902 
903   public void postGetTableNames(final List<HTableDescriptor> descriptors,
904       final String regex) throws IOException {
905     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
906       @Override
907       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
908           throws IOException {
909         oserver.postGetTableNames(ctx, descriptors, regex);
910       }
911     });
912   }
913 
914   public void preTableFlush(final TableName tableName) throws IOException {
915     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
916       @Override
917       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
918           throws IOException {
919         oserver.preTableFlush(ctx, tableName);
920       }
921     });
922   }
923 
924   public void postTableFlush(final TableName tableName) throws IOException {
925     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
926       @Override
927       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
928           throws IOException {
929         oserver.postTableFlush(ctx, tableName);
930       }
931     });
932   }
933 
934   private static abstract class CoprocessorOperation
935       extends ObserverContext<MasterCoprocessorEnvironment> {
936     public CoprocessorOperation() {
937     }
938 
939     public abstract void call(MasterObserver oserver,
940         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
941 
942     public void postEnvCall(MasterEnvironment env) {
943     }
944   }
945 
946   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
947     private T result = null;
948     public void setResult(final T result) { this.result = result; }
949     public T getResult() { return this.result; }
950   }
951 
952   private <T> T execOperationWithResult(final T defaultValue,
953       final CoprocessorOperationWithResult<T> ctx) throws IOException {
954     if (ctx == null) return defaultValue;
955     ctx.setResult(defaultValue);
956     execOperation(ctx);
957     return ctx.getResult();
958   }
959 
960   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
961     if (ctx == null) return false;
962     boolean bypass = false;
963     for (MasterEnvironment env: coprocessors) {
964       if (env.getInstance() instanceof MasterObserver) {
965         ctx.prepare(env);
966         Thread currentThread = Thread.currentThread();
967         ClassLoader cl = currentThread.getContextClassLoader();
968         try {
969           currentThread.setContextClassLoader(env.getClassLoader());
970           ctx.call((MasterObserver)env.getInstance(), ctx);
971         } catch (Throwable e) {
972           handleCoprocessorThrowable(env, e);
973         } finally {
974           currentThread.setContextClassLoader(cl);
975         }
976         bypass |= ctx.shouldBypass();
977         if (ctx.shouldComplete()) {
978           break;
979         }
980       }
981       ctx.postEnvCall(env);
982     }
983     return bypass;
984   }
985 }