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 org.apache.hadoop.classification.InterfaceAudience;
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.*;
25  import org.apache.hadoop.hbase.coprocessor.*;
26  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
27  
28  import java.io.IOException;
29  import java.util.List;
30  
31  /**
32   * Provides the coprocessor framework and environment for master oriented
33   * operations.  {@link HMaster} interacts with the loaded coprocessors
34   * through this class.
35   */
36  @InterfaceAudience.Private
37  public class MasterCoprocessorHost
38      extends CoprocessorHost<MasterCoprocessorHost.MasterEnvironment> {
39  
40    /**
41     * Coprocessor environment extension providing access to master related
42     * services.
43     */
44    static class MasterEnvironment extends CoprocessorHost.Environment
45        implements MasterCoprocessorEnvironment {
46      private MasterServices masterServices;
47  
48      public MasterEnvironment(final Class<?> implClass, final Coprocessor impl,
49          final int priority, final int seq, final Configuration conf,
50          final MasterServices services) {
51        super(impl, priority, seq, conf);
52        this.masterServices = services;
53      }
54  
55      public MasterServices getMasterServices() {
56        return masterServices;
57      }
58    }
59  
60    private MasterServices masterServices;
61  
62    MasterCoprocessorHost(final MasterServices services, final Configuration conf) {
63      super(services);
64      this.conf = conf;
65      this.masterServices = services;
66      loadSystemCoprocessors(conf, MASTER_COPROCESSOR_CONF_KEY);
67    }
68  
69    @Override
70    public MasterEnvironment createEnvironment(final Class<?> implClass,
71        final Coprocessor instance, final int priority, final int seq,
72        final Configuration conf) {
73      for (Class<?> c : implClass.getInterfaces()) {
74        if (CoprocessorService.class.isAssignableFrom(c)) {
75          masterServices.registerService(((CoprocessorService)instance).getService());
76        }
77      }
78      return new MasterEnvironment(implClass, instance, priority, seq, conf,
79          masterServices);
80    }
81  
82    public boolean preCreateNamespace(final NamespaceDescriptor ns) throws IOException {
83      return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
84        @Override
85        public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
86            throws IOException {
87          oserver.preCreateNamespace(ctx, ns);
88        }
89      });
90    }
91  
92    public void postCreateNamespace(final NamespaceDescriptor ns) throws IOException {
93      execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
94        @Override
95        public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
96            throws IOException {
97          oserver.postCreateNamespace(ctx, ns);
98        }
99      });
100   }
101 
102   public boolean preDeleteNamespace(final String namespaceName) throws IOException {
103     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
104       @Override
105       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
106           throws IOException {
107         oserver.preDeleteNamespace(ctx, namespaceName);
108       }
109     });
110   }
111 
112   public void postDeleteNamespace(final String namespaceName) throws IOException {
113     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
114       @Override
115       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
116           throws IOException {
117         oserver.postDeleteNamespace(ctx, namespaceName);
118       }
119     });
120   }
121 
122   public boolean preModifyNamespace(final NamespaceDescriptor ns) throws IOException {
123     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
124       @Override
125       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
126           throws IOException {
127         oserver.preModifyNamespace(ctx, ns);
128       }
129     });
130   }
131 
132   public void postModifyNamespace(final NamespaceDescriptor ns) throws IOException {
133     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
134       @Override
135       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
136           throws IOException {
137         oserver.postModifyNamespace(ctx, ns);
138       }
139     });
140   }
141 
142   /* Implementation of hooks for invoking MasterObservers */
143 
144   public void preCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
145       throws IOException {
146     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
147       @Override
148       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
149           throws IOException {
150         oserver.preCreateTable(ctx, htd, regions);
151       }
152     });
153   }
154 
155   public void postCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
156       throws IOException {
157     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
158       @Override
159       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
160           throws IOException {
161         oserver.postCreateTable(ctx, htd, regions);
162       }
163     });
164   }
165 
166   public void preCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
167       throws IOException {
168     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
169       @Override
170       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
171           throws IOException {
172         oserver.preCreateTableHandler(ctx, htd, regions);
173       }
174     });
175   }
176 
177   public void postCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
178       throws IOException {
179     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
180       @Override
181       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
182           throws IOException {
183         oserver.postCreateTableHandler(ctx, htd, regions);
184       }
185     });
186   }
187 
188   public void preDeleteTable(final TableName tableName) throws IOException {
189     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
190       @Override
191       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
192           throws IOException {
193         oserver.preDeleteTable(ctx, tableName);
194       }
195     });
196   }
197 
198   public void postDeleteTable(final TableName tableName) throws IOException {
199     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
200       @Override
201       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
202           throws IOException {
203         oserver.postDeleteTable(ctx, tableName);
204       }
205     });
206   }
207 
208   public void preDeleteTableHandler(final TableName tableName) 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.preDeleteTableHandler(ctx, tableName);
214       }
215     });
216   }
217 
218   public void postDeleteTableHandler(final TableName tableName) throws IOException {
219     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
220       @Override
221       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
222           throws IOException {
223         oserver.postDeleteTableHandler(ctx, tableName);
224       }
225     });
226   }
227 
228   public void preModifyTable(final TableName tableName, final HTableDescriptor htd)
229       throws IOException {
230     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
231       @Override
232       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
233           throws IOException {
234         oserver.preModifyTable(ctx, tableName, htd);
235       }
236     });
237   }
238 
239   public void postModifyTable(final TableName tableName, final HTableDescriptor htd)
240       throws IOException {
241     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
242       @Override
243       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
244           throws IOException {
245         oserver.postModifyTable(ctx, tableName, htd);
246       }
247     });
248   }
249 
250   public void preModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
251       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.preModifyTableHandler(ctx, tableName, htd);
257       }
258     });
259   }
260 
261   public void postModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
262       throws IOException {
263     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
264       @Override
265       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
266           throws IOException {
267         oserver.postModifyTableHandler(ctx, tableName, htd);
268       }
269     });
270   }
271 
272   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor column)
273       throws IOException {
274     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
275       @Override
276       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
277           throws IOException {
278         oserver.preAddColumn(ctx, tableName, column);
279       }
280     });
281   }
282 
283   public void postAddColumn(final TableName tableName, final HColumnDescriptor column)
284       throws IOException {
285     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
286       @Override
287       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
288           throws IOException {
289         oserver.postAddColumn(ctx, tableName, column);
290       }
291     });
292   }
293 
294   public boolean preAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
295       throws IOException {
296     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
297       @Override
298       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
299           throws IOException {
300         oserver.preAddColumnHandler(ctx, tableName, column);
301       }
302     });
303   }
304 
305   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
306       throws IOException {
307     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
308       @Override
309       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
310           throws IOException {
311         oserver.postAddColumnHandler(ctx, tableName, column);
312       }
313     });
314   }
315 
316   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
317       throws IOException {
318     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
319       @Override
320       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
321           throws IOException {
322         oserver.preModifyColumn(ctx, tableName, descriptor);
323       }
324     });
325   }
326 
327   public void postModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
328       throws IOException {
329     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
330       @Override
331       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
332           throws IOException {
333         oserver.postModifyColumn(ctx, tableName, descriptor);
334       }
335     });
336   }
337 
338   public boolean preModifyColumnHandler(final TableName tableName,
339       final HColumnDescriptor descriptor) throws IOException {
340     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
341       @Override
342       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
343           throws IOException {
344         oserver.preModifyColumnHandler(ctx, tableName, descriptor);
345       }
346     });
347   }
348 
349   public void postModifyColumnHandler(final TableName tableName,
350       final HColumnDescriptor descriptor) throws IOException {
351     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
352       @Override
353       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
354           throws IOException {
355         oserver.postModifyColumnHandler(ctx, tableName, descriptor);
356       }
357     });
358   }
359 
360   public boolean preDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
361     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
362       @Override
363       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
364           throws IOException {
365         oserver.preDeleteColumn(ctx, tableName, c);
366       }
367     });
368   }
369 
370   public void postDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
371     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
372       @Override
373       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
374           throws IOException {
375         oserver.postDeleteColumn(ctx, tableName, c);
376       }
377     });
378   }
379 
380   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] c)
381       throws IOException {
382     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
383       @Override
384       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
385           throws IOException {
386         oserver.preDeleteColumnHandler(ctx, tableName, c);
387       }
388     });
389   }
390 
391   public void postDeleteColumnHandler(final TableName tableName, final byte[] c)
392       throws IOException {
393     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
394       @Override
395       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
396           throws IOException {
397         oserver.postDeleteColumnHandler(ctx, tableName, c);
398       }
399     });
400   }
401 
402   public void preEnableTable(final TableName tableName) throws IOException {
403     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
404       @Override
405       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
406           throws IOException {
407         oserver.preEnableTable(ctx, tableName);
408       }
409     });
410   }
411 
412   public void postEnableTable(final TableName tableName) throws IOException {
413     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
414       @Override
415       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
416           throws IOException {
417         oserver.postEnableTable(ctx, tableName);
418       }
419     });
420   }
421 
422   public void preEnableTableHandler(final TableName tableName) throws IOException {
423     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
424       @Override
425       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
426           throws IOException {
427         oserver.preEnableTableHandler(ctx, tableName);
428       }
429     });
430   }
431 
432   public void postEnableTableHandler(final TableName tableName) throws IOException {
433     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
434       @Override
435       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
436           throws IOException {
437         oserver.postEnableTableHandler(ctx, tableName);
438       }
439     });
440   }
441 
442   public void preDisableTable(final TableName tableName) throws IOException {
443     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
444       @Override
445       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
446           throws IOException {
447         oserver.preDisableTable(ctx, tableName);
448       }
449     });
450   }
451 
452   public void postDisableTable(final TableName tableName) throws IOException {
453     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
454       @Override
455       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
456           throws IOException {
457         oserver.postDisableTable(ctx, tableName);
458       }
459     });
460   }
461 
462   public void preDisableTableHandler(final TableName tableName) throws IOException {
463     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
464       @Override
465       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
466           throws IOException {
467         oserver.preDisableTableHandler(ctx, tableName);
468       }
469     });
470   }
471 
472   public void postDisableTableHandler(final TableName tableName) throws IOException {
473     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
474       @Override
475       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
476           throws IOException {
477         oserver.postDisableTableHandler(ctx, tableName);
478       }
479     });
480   }
481 
482   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
483       final ServerName destServer) throws IOException {
484     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
485       @Override
486       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
487           throws IOException {
488         oserver.preMove(ctx, region, srcServer, destServer);
489       }
490     });
491   }
492 
493   public void postMove(final HRegionInfo region, final ServerName srcServer,
494       final ServerName destServer) throws IOException {
495     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
496       @Override
497       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
498           throws IOException {
499         oserver.postMove(ctx, region, srcServer, destServer);
500       }
501     });
502   }
503 
504   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
505     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
506       @Override
507       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
508           throws IOException {
509         oserver.preAssign(ctx, regionInfo);
510       }
511     });
512   }
513 
514   public void postAssign(final HRegionInfo regionInfo) throws IOException {
515     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
516       @Override
517       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
518           throws IOException {
519         oserver.postAssign(ctx, regionInfo);
520       }
521     });
522   }
523 
524   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
525       throws IOException {
526     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
527       @Override
528       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
529           throws IOException {
530         oserver.preUnassign(ctx, regionInfo, force);
531       }
532     });
533   }
534 
535   public void postUnassign(final HRegionInfo regionInfo, final boolean force) 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.postUnassign(ctx, regionInfo, force);
541       }
542     });
543   }
544 
545   public void preRegionOffline(final HRegionInfo regionInfo) 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.preRegionOffline(ctx, regionInfo);
551       }
552     });
553   }
554 
555   public void postRegionOffline(final HRegionInfo regionInfo) 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.postRegionOffline(ctx, regionInfo);
561       }
562     });
563   }
564 
565   public boolean preBalance() throws IOException {
566     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
567       @Override
568       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
569           throws IOException {
570         oserver.preBalance(ctx);
571       }
572     });
573   }
574 
575   public void postBalance(final List<RegionPlan> plans) 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.postBalance(ctx, plans);
581       }
582     });
583   }
584 
585   public boolean preBalanceSwitch(final boolean b) throws IOException {
586     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
587         new CoprocessorOperationWithResult<Boolean>() {
588       @Override
589       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
590           throws IOException {
591         setResult(oserver.preBalanceSwitch(ctx, getResult()));
592       }
593     });
594   }
595 
596   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
597       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.postBalanceSwitch(ctx, oldValue, newValue);
603       }
604     });
605   }
606 
607   public void preShutdown() throws IOException {
608     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
609       @Override
610       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
611           throws IOException {
612         oserver.preShutdown(ctx);
613       }
614       @Override
615       public void postEnvCall(MasterEnvironment env) {
616         // invoke coprocessor stop method
617         shutdown(env);
618       }
619     });
620   }
621 
622   public void preStopMaster() throws IOException {
623     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
624       @Override
625       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
626           throws IOException {
627         oserver.preStopMaster(ctx);
628       }
629       @Override
630       public void postEnvCall(MasterEnvironment env) {
631         // invoke coprocessor stop method
632         shutdown(env);
633       }
634     });
635   }
636 
637   public void preMasterInitialization() throws IOException {
638     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
639       @Override
640       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
641           throws IOException {
642         oserver.preMasterInitialization(ctx);
643       }
644     });
645   }
646 
647   public void postStartMaster() throws IOException {
648     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
649       @Override
650       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
651           throws IOException {
652         oserver.postStartMaster(ctx);
653       }
654     });
655   }
656 
657   public void preSnapshot(final SnapshotDescription snapshot,
658       final HTableDescriptor hTableDescriptor) 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.preSnapshot(ctx, snapshot, hTableDescriptor);
664       }
665     });
666   }
667 
668   public void postSnapshot(final SnapshotDescription snapshot,
669       final HTableDescriptor hTableDescriptor) throws IOException {
670     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
671       @Override
672       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
673           throws IOException {
674         oserver.postSnapshot(ctx, snapshot, hTableDescriptor);
675       }
676     });
677   }
678 
679   public void preCloneSnapshot(final SnapshotDescription snapshot,
680       final HTableDescriptor hTableDescriptor) throws IOException {
681     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
682       @Override
683       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
684           throws IOException {
685         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
686       }
687     });
688   }
689 
690   public void postCloneSnapshot(final SnapshotDescription snapshot,
691       final HTableDescriptor hTableDescriptor) throws IOException {
692     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
693       @Override
694       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
695           throws IOException {
696         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
697       }
698     });
699   }
700 
701   public void preRestoreSnapshot(final SnapshotDescription snapshot,
702       final HTableDescriptor hTableDescriptor) throws IOException {
703     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
704       @Override
705       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
706           throws IOException {
707         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
708       }
709     });
710   }
711 
712   public void postRestoreSnapshot(final SnapshotDescription snapshot,
713       final HTableDescriptor hTableDescriptor) throws IOException {
714     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
715       @Override
716       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
717           throws IOException {
718         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
719       }
720     });
721   }
722 
723   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
724     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
725       @Override
726       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
727           throws IOException {
728         oserver.preDeleteSnapshot(ctx, snapshot);
729       }
730     });
731   }
732 
733   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
734     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
735       @Override
736       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
737           throws IOException {
738         oserver.postDeleteSnapshot(ctx, snapshot);
739       }
740     });
741   }
742 
743   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
744       final List<HTableDescriptor> descriptors) throws IOException {
745     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
746       @Override
747       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
748           throws IOException {
749         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors);
750       }
751     });
752   }
753 
754   public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
755       throws IOException {
756     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
757       @Override
758       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
759           throws IOException {
760         oserver.postGetTableDescriptors(ctx, descriptors);
761       }
762     });
763   }
764 
765   private static abstract class CoprocessorOperation
766       extends ObserverContext<MasterCoprocessorEnvironment> {
767     public CoprocessorOperation() {
768     }
769 
770     public abstract void call(MasterObserver oserver,
771         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
772 
773     public void postEnvCall(MasterEnvironment env) {
774     }
775   }
776 
777   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
778     private T result = null;
779     public void setResult(final T result) { this.result = result; }
780     public T getResult() { return this.result; }
781   }
782 
783   private <T> T execOperationWithResult(final T defaultValue,
784       final CoprocessorOperationWithResult<T> ctx) throws IOException {
785     if (ctx == null) return defaultValue;
786     ctx.setResult(defaultValue);
787     execOperation(ctx);
788     return ctx.getResult();
789   }
790 
791   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
792     if (ctx == null) return false;
793     boolean bypass = false;
794     for (MasterEnvironment env: coprocessors) {
795       if (env.getInstance() instanceof MasterObserver) {
796         ctx.prepare(env);
797         Thread currentThread = Thread.currentThread();
798         ClassLoader cl = currentThread.getContextClassLoader();
799         try {
800           currentThread.setContextClassLoader(env.getClassLoader());
801           ctx.call((MasterObserver)env.getInstance(), ctx);
802         } catch (Throwable e) {
803           handleCoprocessorThrowable(env, e);
804         } finally {
805           currentThread.setContextClassLoader(cl);
806         }
807         bypass |= ctx.shouldBypass();
808         if (ctx.shouldComplete()) {
809           break;
810         }
811       }
812       ctx.postEnvCall(env);
813     }
814     return bypass;
815   }
816 }