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