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  
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 preTruncateTable(TableName tableName) throws IOException {
229     ObserverContext<MasterCoprocessorEnvironment> ctx = null;
230     for (MasterEnvironment env: coprocessors) {
231       if (env.getInstance() instanceof MasterObserver) {
232         ctx = ObserverContext.createAndPrepare(env, ctx);
233         try {
234           ((MasterObserver)env.getInstance()).preTruncateTable(ctx, tableName);
235         } catch (Throwable e) {
236           handleCoprocessorThrowable(env, e);
237         }
238         if (ctx.shouldComplete()) {
239           break;
240         }
241       }
242     }
243   }
244 
245   public void postTruncateTable(TableName tableName) throws IOException {
246     ObserverContext<MasterCoprocessorEnvironment> ctx = null;
247     for (MasterEnvironment env: coprocessors) {
248       if (env.getInstance() instanceof MasterObserver) {
249         ctx = ObserverContext.createAndPrepare(env, ctx);
250         try {
251           ((MasterObserver)env.getInstance()).postTruncateTable(ctx, tableName);
252         } catch (Throwable e) {
253           handleCoprocessorThrowable(env, e);
254         }
255         if (ctx.shouldComplete()) {
256           break;
257         }
258       }
259     }
260   }
261 
262   public void preTruncateTableHandler(TableName tableName) throws IOException {
263     ObserverContext<MasterCoprocessorEnvironment> ctx = null;
264     for (MasterEnvironment env : coprocessors) {
265       if (env.getInstance() instanceof MasterObserver) {
266         ctx = ObserverContext.createAndPrepare(env, ctx);
267         try {
268           ((MasterObserver) env.getInstance()).preTruncateTableHandler(ctx, tableName);
269         } catch (Throwable e) {
270           handleCoprocessorThrowable(env, e);
271         }
272         if (ctx.shouldComplete()) {
273           break;
274         }
275       }
276     }
277   }
278 
279   public void postTruncateTableHandler(TableName tableName) throws IOException {
280     ObserverContext<MasterCoprocessorEnvironment> ctx = null;
281     for (MasterEnvironment env : coprocessors) {
282       if (env.getInstance() instanceof MasterObserver) {
283         ctx = ObserverContext.createAndPrepare(env, ctx);
284         try {
285           ((MasterObserver) env.getInstance()).postTruncateTableHandler(ctx, tableName);
286         } catch (Throwable e) {
287           handleCoprocessorThrowable(env, e);
288         }
289         if (ctx.shouldComplete()) {
290           break;
291         }
292       }
293     }
294   }
295 
296   public void preModifyTable(final TableName tableName, final HTableDescriptor htd)
297       throws IOException {
298     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
299       @Override
300       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
301           throws IOException {
302         oserver.preModifyTable(ctx, tableName, htd);
303       }
304     });
305   }
306 
307   public void postModifyTable(final TableName tableName, final HTableDescriptor htd)
308       throws IOException {
309     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
310       @Override
311       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
312           throws IOException {
313         oserver.postModifyTable(ctx, tableName, htd);
314       }
315     });
316   }
317 
318   public void preModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
319       throws IOException {
320     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
321       @Override
322       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
323           throws IOException {
324         oserver.preModifyTableHandler(ctx, tableName, htd);
325       }
326     });
327   }
328 
329   public void postModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
330       throws IOException {
331     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
332       @Override
333       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
334           throws IOException {
335         oserver.postModifyTableHandler(ctx, tableName, htd);
336       }
337     });
338   }
339 
340   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor column)
341       throws IOException {
342     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
343       @Override
344       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
345           throws IOException {
346         oserver.preAddColumn(ctx, tableName, column);
347       }
348     });
349   }
350 
351   public void postAddColumn(final TableName tableName, final HColumnDescriptor column)
352       throws IOException {
353     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
354       @Override
355       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
356           throws IOException {
357         oserver.postAddColumn(ctx, tableName, column);
358       }
359     });
360   }
361 
362   public boolean preAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
363       throws IOException {
364     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
365       @Override
366       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
367           throws IOException {
368         oserver.preAddColumnHandler(ctx, tableName, column);
369       }
370     });
371   }
372 
373   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
374       throws IOException {
375     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
376       @Override
377       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
378           throws IOException {
379         oserver.postAddColumnHandler(ctx, tableName, column);
380       }
381     });
382   }
383 
384   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
385       throws IOException {
386     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
387       @Override
388       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
389           throws IOException {
390         oserver.preModifyColumn(ctx, tableName, descriptor);
391       }
392     });
393   }
394 
395   public void postModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
396       throws IOException {
397     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
398       @Override
399       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
400           throws IOException {
401         oserver.postModifyColumn(ctx, tableName, descriptor);
402       }
403     });
404   }
405 
406   public boolean preModifyColumnHandler(final TableName tableName,
407       final HColumnDescriptor descriptor) throws IOException {
408     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
409       @Override
410       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
411           throws IOException {
412         oserver.preModifyColumnHandler(ctx, tableName, descriptor);
413       }
414     });
415   }
416 
417   public void postModifyColumnHandler(final TableName tableName,
418       final HColumnDescriptor descriptor) throws IOException {
419     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
420       @Override
421       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
422           throws IOException {
423         oserver.postModifyColumnHandler(ctx, tableName, descriptor);
424       }
425     });
426   }
427 
428   public boolean preDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
429     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
430       @Override
431       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
432           throws IOException {
433         oserver.preDeleteColumn(ctx, tableName, c);
434       }
435     });
436   }
437 
438   public void postDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
439     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
440       @Override
441       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
442           throws IOException {
443         oserver.postDeleteColumn(ctx, tableName, c);
444       }
445     });
446   }
447 
448   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] c)
449       throws IOException {
450     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
451       @Override
452       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
453           throws IOException {
454         oserver.preDeleteColumnHandler(ctx, tableName, c);
455       }
456     });
457   }
458 
459   public void postDeleteColumnHandler(final TableName tableName, final byte[] c)
460       throws IOException {
461     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
462       @Override
463       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
464           throws IOException {
465         oserver.postDeleteColumnHandler(ctx, tableName, c);
466       }
467     });
468   }
469 
470   public void preEnableTable(final TableName tableName) throws IOException {
471     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
472       @Override
473       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
474           throws IOException {
475         oserver.preEnableTable(ctx, tableName);
476       }
477     });
478   }
479 
480   public void postEnableTable(final TableName tableName) throws IOException {
481     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
482       @Override
483       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
484           throws IOException {
485         oserver.postEnableTable(ctx, tableName);
486       }
487     });
488   }
489 
490   public void preEnableTableHandler(final TableName tableName) throws IOException {
491     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
492       @Override
493       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
494           throws IOException {
495         oserver.preEnableTableHandler(ctx, tableName);
496       }
497     });
498   }
499 
500   public void postEnableTableHandler(final TableName tableName) throws IOException {
501     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
502       @Override
503       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
504           throws IOException {
505         oserver.postEnableTableHandler(ctx, tableName);
506       }
507     });
508   }
509 
510   public void preDisableTable(final TableName tableName) throws IOException {
511     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
512       @Override
513       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
514           throws IOException {
515         oserver.preDisableTable(ctx, tableName);
516       }
517     });
518   }
519 
520   public void postDisableTable(final TableName tableName) throws IOException {
521     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
522       @Override
523       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
524           throws IOException {
525         oserver.postDisableTable(ctx, tableName);
526       }
527     });
528   }
529 
530   public void preDisableTableHandler(final TableName tableName) throws IOException {
531     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
532       @Override
533       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
534           throws IOException {
535         oserver.preDisableTableHandler(ctx, tableName);
536       }
537     });
538   }
539 
540   public void postDisableTableHandler(final TableName tableName) throws IOException {
541     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
542       @Override
543       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
544           throws IOException {
545         oserver.postDisableTableHandler(ctx, tableName);
546       }
547     });
548   }
549 
550   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
551       final ServerName destServer) throws IOException {
552     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
553       @Override
554       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
555           throws IOException {
556         oserver.preMove(ctx, region, srcServer, destServer);
557       }
558     });
559   }
560 
561   public void postMove(final HRegionInfo region, final ServerName srcServer,
562       final ServerName destServer) throws IOException {
563     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
564       @Override
565       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
566           throws IOException {
567         oserver.postMove(ctx, region, srcServer, destServer);
568       }
569     });
570   }
571 
572   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
573     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
574       @Override
575       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
576           throws IOException {
577         oserver.preAssign(ctx, regionInfo);
578       }
579     });
580   }
581 
582   public void postAssign(final HRegionInfo regionInfo) throws IOException {
583     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
584       @Override
585       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
586           throws IOException {
587         oserver.postAssign(ctx, regionInfo);
588       }
589     });
590   }
591 
592   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
593       throws IOException {
594     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
595       @Override
596       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
597           throws IOException {
598         oserver.preUnassign(ctx, regionInfo, force);
599       }
600     });
601   }
602 
603   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
604     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
605       @Override
606       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
607           throws IOException {
608         oserver.postUnassign(ctx, regionInfo, force);
609       }
610     });
611   }
612 
613   public void preRegionOffline(final HRegionInfo regionInfo) throws IOException {
614     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
615       @Override
616       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
617           throws IOException {
618         oserver.preRegionOffline(ctx, regionInfo);
619       }
620     });
621   }
622 
623   public void postRegionOffline(final HRegionInfo regionInfo) throws IOException {
624     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
625       @Override
626       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
627           throws IOException {
628         oserver.postRegionOffline(ctx, regionInfo);
629       }
630     });
631   }
632 
633   public boolean preBalance() throws IOException {
634     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
635       @Override
636       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
637           throws IOException {
638         oserver.preBalance(ctx);
639       }
640     });
641   }
642 
643   public void postBalance(final List<RegionPlan> plans) throws IOException {
644     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
645       @Override
646       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
647           throws IOException {
648         oserver.postBalance(ctx, plans);
649       }
650     });
651   }
652 
653   public boolean preBalanceSwitch(final boolean b) throws IOException {
654     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
655         new CoprocessorOperationWithResult<Boolean>() {
656       @Override
657       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
658           throws IOException {
659         setResult(oserver.preBalanceSwitch(ctx, getResult()));
660       }
661     });
662   }
663 
664   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
665       throws IOException {
666     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
667       @Override
668       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
669           throws IOException {
670         oserver.postBalanceSwitch(ctx, oldValue, newValue);
671       }
672     });
673   }
674 
675   public void preShutdown() throws IOException {
676     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
677       @Override
678       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
679           throws IOException {
680         oserver.preShutdown(ctx);
681       }
682       @Override
683       public void postEnvCall(MasterEnvironment env) {
684         // invoke coprocessor stop method
685         shutdown(env);
686       }
687     });
688   }
689 
690   public void preStopMaster() throws IOException {
691     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
692       @Override
693       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
694           throws IOException {
695         oserver.preStopMaster(ctx);
696       }
697       @Override
698       public void postEnvCall(MasterEnvironment env) {
699         // invoke coprocessor stop method
700         shutdown(env);
701       }
702     });
703   }
704 
705   public void preMasterInitialization() throws IOException {
706     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
707       @Override
708       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
709           throws IOException {
710         oserver.preMasterInitialization(ctx);
711       }
712     });
713   }
714 
715   public void postStartMaster() throws IOException {
716     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
717       @Override
718       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
719           throws IOException {
720         oserver.postStartMaster(ctx);
721       }
722     });
723   }
724 
725   public void preSnapshot(final SnapshotDescription snapshot,
726       final HTableDescriptor hTableDescriptor) throws IOException {
727     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
728       @Override
729       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
730           throws IOException {
731         oserver.preSnapshot(ctx, snapshot, hTableDescriptor);
732       }
733     });
734   }
735 
736   public void postSnapshot(final SnapshotDescription snapshot,
737       final HTableDescriptor hTableDescriptor) throws IOException {
738     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
739       @Override
740       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
741           throws IOException {
742         oserver.postSnapshot(ctx, snapshot, hTableDescriptor);
743       }
744     });
745   }
746 
747   public void preCloneSnapshot(final SnapshotDescription snapshot,
748       final HTableDescriptor hTableDescriptor) throws IOException {
749     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
750       @Override
751       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
752           throws IOException {
753         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
754       }
755     });
756   }
757 
758   public void postCloneSnapshot(final SnapshotDescription snapshot,
759       final HTableDescriptor hTableDescriptor) throws IOException {
760     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
761       @Override
762       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
763           throws IOException {
764         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
765       }
766     });
767   }
768 
769   public void preRestoreSnapshot(final SnapshotDescription snapshot,
770       final HTableDescriptor hTableDescriptor) throws IOException {
771     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
772       @Override
773       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
774           throws IOException {
775         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
776       }
777     });
778   }
779 
780   public void postRestoreSnapshot(final SnapshotDescription snapshot,
781       final HTableDescriptor hTableDescriptor) throws IOException {
782     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
783       @Override
784       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
785           throws IOException {
786         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
787       }
788     });
789   }
790 
791   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
792     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
793       @Override
794       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
795           throws IOException {
796         oserver.preDeleteSnapshot(ctx, snapshot);
797       }
798     });
799   }
800 
801   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
802     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
803       @Override
804       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
805           throws IOException {
806         oserver.postDeleteSnapshot(ctx, snapshot);
807       }
808     });
809   }
810 
811   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
812       final List<HTableDescriptor> descriptors) throws IOException {
813     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
814       @Override
815       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
816           throws IOException {
817         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors);
818       }
819     });
820   }
821 
822   public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
823       throws IOException {
824     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
825       @Override
826       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
827           throws IOException {
828         oserver.postGetTableDescriptors(ctx, descriptors);
829       }
830     });
831   }
832 
833   private static abstract class CoprocessorOperation
834       extends ObserverContext<MasterCoprocessorEnvironment> {
835     public CoprocessorOperation() {
836     }
837 
838     public abstract void call(MasterObserver oserver,
839         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
840 
841     public void postEnvCall(MasterEnvironment env) {
842     }
843   }
844 
845   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
846     private T result = null;
847     public void setResult(final T result) { this.result = result; }
848     public T getResult() { return this.result; }
849   }
850 
851   private <T> T execOperationWithResult(final T defaultValue,
852       final CoprocessorOperationWithResult<T> ctx) throws IOException {
853     if (ctx == null) return defaultValue;
854     ctx.setResult(defaultValue);
855     execOperation(ctx);
856     return ctx.getResult();
857   }
858 
859   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
860     if (ctx == null) return false;
861     boolean bypass = false;
862     for (MasterEnvironment env: coprocessors) {
863       if (env.getInstance() instanceof MasterObserver) {
864         ctx.prepare(env);
865         Thread currentThread = Thread.currentThread();
866         ClassLoader cl = currentThread.getContextClassLoader();
867         try {
868           currentThread.setContextClassLoader(env.getClassLoader());
869           ctx.call((MasterObserver)env.getInstance(), ctx);
870         } catch (Throwable e) {
871           handleCoprocessorThrowable(env, e);
872         } finally {
873           currentThread.setContextClassLoader(cl);
874         }
875         bypass |= ctx.shouldBypass();
876         if (ctx.shouldComplete()) {
877           break;
878         }
879       }
880       ctx.postEnvCall(env);
881     }
882     return bypass;
883   }
884 }