View Javadoc

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