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.hadoop.conf.Configuration;
26  import org.apache.hadoop.hbase.Coprocessor;
27  import org.apache.hadoop.hbase.HColumnDescriptor;
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.HTableDescriptor;
30  import org.apache.hadoop.hbase.NamespaceDescriptor;
31  import org.apache.hadoop.hbase.ServerName;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.classification.InterfaceAudience;
34  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
35  import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
36  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
37  import org.apache.hadoop.hbase.coprocessor.MasterObserver;
38  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
39  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
40  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
41  
42  /**
43   * Provides the coprocessor framework and environment for master oriented
44   * operations.  {@link HMaster} interacts with the loaded coprocessors
45   * through this class.
46   */
47  @InterfaceAudience.Private
48  public class MasterCoprocessorHost
49      extends CoprocessorHost<MasterCoprocessorHost.MasterEnvironment> {
50  
51    /**
52     * Coprocessor environment extension providing access to master related
53     * services.
54     */
55    static class MasterEnvironment extends CoprocessorHost.Environment
56        implements MasterCoprocessorEnvironment {
57      private MasterServices masterServices;
58  
59      public MasterEnvironment(final Class<?> implClass, final Coprocessor impl,
60          final int priority, final int seq, final Configuration conf,
61          final MasterServices services) {
62        super(impl, priority, seq, conf);
63        this.masterServices = services;
64      }
65  
66      public MasterServices getMasterServices() {
67        return masterServices;
68      }
69    }
70  
71    private MasterServices masterServices;
72  
73    MasterCoprocessorHost(final MasterServices services, final Configuration conf) {
74      super(services);
75      this.conf = conf;
76      this.masterServices = services;
77      loadSystemCoprocessors(conf, MASTER_COPROCESSOR_CONF_KEY);
78    }
79  
80    @Override
81    public MasterEnvironment createEnvironment(final Class<?> implClass,
82        final Coprocessor instance, final int priority, final int seq,
83        final Configuration conf) {
84      for (Class<?> c : implClass.getInterfaces()) {
85        if (CoprocessorService.class.isAssignableFrom(c)) {
86          masterServices.registerService(((CoprocessorService)instance).getService());
87        }
88      }
89      return new MasterEnvironment(implClass, instance, priority, seq, conf,
90          masterServices);
91    }
92  
93    public boolean preCreateNamespace(final NamespaceDescriptor ns) throws IOException {
94      return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
95        @Override
96        public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
97            throws IOException {
98          oserver.preCreateNamespace(ctx, ns);
99        }
100     });
101   }
102 
103   public void postCreateNamespace(final NamespaceDescriptor ns) throws IOException {
104     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
105       @Override
106       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
107           throws IOException {
108         oserver.postCreateNamespace(ctx, ns);
109       }
110     });
111   }
112 
113   public boolean preDeleteNamespace(final String namespaceName) throws IOException {
114     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
115       @Override
116       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
117           throws IOException {
118         oserver.preDeleteNamespace(ctx, namespaceName);
119       }
120     });
121   }
122 
123   public void postDeleteNamespace(final String namespaceName) throws IOException {
124     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
125       @Override
126       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
127           throws IOException {
128         oserver.postDeleteNamespace(ctx, namespaceName);
129       }
130     });
131   }
132 
133   public boolean preModifyNamespace(final NamespaceDescriptor ns) throws IOException {
134     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
135       @Override
136       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
137           throws IOException {
138         oserver.preModifyNamespace(ctx, ns);
139       }
140     });
141   }
142 
143   public void postModifyNamespace(final NamespaceDescriptor ns) throws IOException {
144     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
145       @Override
146       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
147           throws IOException {
148         oserver.postModifyNamespace(ctx, ns);
149       }
150     });
151   }
152 
153   public void preGetNamespaceDescriptor(final String namespaceName)
154       throws IOException {
155     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
156       @Override
157       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
158           throws IOException {
159         oserver.preGetNamespaceDescriptor(ctx, namespaceName);
160       }
161     });
162   }
163 
164   public void postGetNamespaceDescriptor(final NamespaceDescriptor ns)
165       throws IOException {
166     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
167       @Override
168       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
169           throws IOException {
170         oserver.postGetNamespaceDescriptor(ctx, ns);
171       }
172     });
173   }
174 
175   public boolean preListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
176       throws IOException {
177     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
178       @Override
179       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
180           throws IOException {
181         oserver.preListNamespaceDescriptors(ctx, descriptors);
182       }
183     });
184   }
185 
186   public void postListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
187       throws IOException {
188     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
189       @Override
190       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
191           throws IOException {
192         oserver.postListNamespaceDescriptors(ctx, descriptors);
193       }
194     });
195   }
196 
197   /* Implementation of hooks for invoking MasterObservers */
198 
199   public void preCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
200       throws IOException {
201     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
202       @Override
203       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
204           throws IOException {
205         oserver.preCreateTable(ctx, htd, regions);
206       }
207     });
208   }
209 
210   public void postCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
211       throws IOException {
212     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
213       @Override
214       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
215           throws IOException {
216         oserver.postCreateTable(ctx, htd, regions);
217       }
218     });
219   }
220 
221   public void preCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
222       throws IOException {
223     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
224       @Override
225       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
226           throws IOException {
227         oserver.preCreateTableHandler(ctx, htd, regions);
228       }
229     });
230   }
231 
232   public void postCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
233       throws IOException {
234     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
235       @Override
236       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
237           throws IOException {
238         oserver.postCreateTableHandler(ctx, htd, regions);
239       }
240     });
241   }
242 
243   public void preDeleteTable(final TableName tableName) 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.preDeleteTable(ctx, tableName);
249       }
250     });
251   }
252 
253   public void postDeleteTable(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.postDeleteTable(ctx, tableName);
259       }
260     });
261   }
262 
263   public void preDeleteTableHandler(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.preDeleteTableHandler(ctx, tableName);
269       }
270     });
271   }
272 
273   public void postDeleteTableHandler(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.postDeleteTableHandler(ctx, tableName);
279       }
280     });
281   }
282 
283   public void preTruncateTable(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.preTruncateTable(ctx, tableName);
289       }
290     });
291   }
292 
293   public void postTruncateTable(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.postTruncateTable(ctx, tableName);
299       }
300     });
301   }
302 
303   public void preTruncateTableHandler(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.preTruncateTableHandler(ctx, tableName);
309       }
310     });
311   }
312 
313   public void postTruncateTableHandler(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.postTruncateTableHandler(ctx, tableName);
319       }
320     });
321   }
322 
323   public void preModifyTable(final TableName tableName, final HTableDescriptor htd)
324       throws IOException {
325     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
326       @Override
327       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
328           throws IOException {
329         oserver.preModifyTable(ctx, tableName, htd);
330       }
331     });
332   }
333 
334   public void postModifyTable(final TableName tableName, final HTableDescriptor htd)
335       throws IOException {
336     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
337       @Override
338       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
339           throws IOException {
340         oserver.postModifyTable(ctx, tableName, htd);
341       }
342     });
343   }
344 
345   public void preModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
346       throws IOException {
347     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
348       @Override
349       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
350           throws IOException {
351         oserver.preModifyTableHandler(ctx, tableName, htd);
352       }
353     });
354   }
355 
356   public void postModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
357       throws IOException {
358     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
359       @Override
360       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
361           throws IOException {
362         oserver.postModifyTableHandler(ctx, tableName, htd);
363       }
364     });
365   }
366 
367   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor column)
368       throws IOException {
369     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
370       @Override
371       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
372           throws IOException {
373         oserver.preAddColumn(ctx, tableName, column);
374       }
375     });
376   }
377 
378   public void postAddColumn(final TableName tableName, final HColumnDescriptor column)
379       throws IOException {
380     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
381       @Override
382       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
383           throws IOException {
384         oserver.postAddColumn(ctx, tableName, column);
385       }
386     });
387   }
388 
389   public boolean preAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
390       throws IOException {
391     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
392       @Override
393       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
394           throws IOException {
395         oserver.preAddColumnHandler(ctx, tableName, column);
396       }
397     });
398   }
399 
400   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
401       throws IOException {
402     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
403       @Override
404       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
405           throws IOException {
406         oserver.postAddColumnHandler(ctx, tableName, column);
407       }
408     });
409   }
410 
411   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
412       throws IOException {
413     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
414       @Override
415       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
416           throws IOException {
417         oserver.preModifyColumn(ctx, tableName, descriptor);
418       }
419     });
420   }
421 
422   public void postModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
423       throws IOException {
424     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
425       @Override
426       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
427           throws IOException {
428         oserver.postModifyColumn(ctx, tableName, descriptor);
429       }
430     });
431   }
432 
433   public boolean preModifyColumnHandler(final TableName tableName,
434       final HColumnDescriptor descriptor) throws IOException {
435     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
436       @Override
437       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
438           throws IOException {
439         oserver.preModifyColumnHandler(ctx, tableName, descriptor);
440       }
441     });
442   }
443 
444   public void postModifyColumnHandler(final TableName tableName,
445       final HColumnDescriptor descriptor) throws IOException {
446     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
447       @Override
448       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
449           throws IOException {
450         oserver.postModifyColumnHandler(ctx, tableName, descriptor);
451       }
452     });
453   }
454 
455   public boolean preDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
456     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
457       @Override
458       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
459           throws IOException {
460         oserver.preDeleteColumn(ctx, tableName, c);
461       }
462     });
463   }
464 
465   public void postDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
466     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
467       @Override
468       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
469           throws IOException {
470         oserver.postDeleteColumn(ctx, tableName, c);
471       }
472     });
473   }
474 
475   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] c)
476       throws IOException {
477     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
478       @Override
479       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
480           throws IOException {
481         oserver.preDeleteColumnHandler(ctx, tableName, c);
482       }
483     });
484   }
485 
486   public void postDeleteColumnHandler(final TableName tableName, final byte[] c)
487       throws IOException {
488     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
489       @Override
490       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
491           throws IOException {
492         oserver.postDeleteColumnHandler(ctx, tableName, c);
493       }
494     });
495   }
496 
497   public void preEnableTable(final TableName tableName) 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.preEnableTable(ctx, tableName);
503       }
504     });
505   }
506 
507   public void postEnableTable(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.postEnableTable(ctx, tableName);
513       }
514     });
515   }
516 
517   public void preEnableTableHandler(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.preEnableTableHandler(ctx, tableName);
523       }
524     });
525   }
526 
527   public void postEnableTableHandler(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.postEnableTableHandler(ctx, tableName);
533       }
534     });
535   }
536 
537   public void preDisableTable(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.preDisableTable(ctx, tableName);
543       }
544     });
545   }
546 
547   public void postDisableTable(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.postDisableTable(ctx, tableName);
553       }
554     });
555   }
556 
557   public void preDisableTableHandler(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.preDisableTableHandler(ctx, tableName);
563       }
564     });
565   }
566 
567   public void postDisableTableHandler(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.postDisableTableHandler(ctx, tableName);
573       }
574     });
575   }
576 
577   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
578       final ServerName destServer) throws IOException {
579     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
580       @Override
581       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
582           throws IOException {
583         oserver.preMove(ctx, region, srcServer, destServer);
584       }
585     });
586   }
587 
588   public void postMove(final HRegionInfo region, final ServerName srcServer,
589       final ServerName destServer) throws IOException {
590     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
591       @Override
592       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
593           throws IOException {
594         oserver.postMove(ctx, region, srcServer, destServer);
595       }
596     });
597   }
598 
599   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
600     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
601       @Override
602       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
603           throws IOException {
604         oserver.preAssign(ctx, regionInfo);
605       }
606     });
607   }
608 
609   public void postAssign(final HRegionInfo regionInfo) throws IOException {
610     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
611       @Override
612       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
613           throws IOException {
614         oserver.postAssign(ctx, regionInfo);
615       }
616     });
617   }
618 
619   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
620       throws IOException {
621     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
622       @Override
623       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
624           throws IOException {
625         oserver.preUnassign(ctx, regionInfo, force);
626       }
627     });
628   }
629 
630   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
631     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
632       @Override
633       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
634           throws IOException {
635         oserver.postUnassign(ctx, regionInfo, force);
636       }
637     });
638   }
639 
640   public void preRegionOffline(final HRegionInfo regionInfo) 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.preRegionOffline(ctx, regionInfo);
646       }
647     });
648   }
649 
650   public void postRegionOffline(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.postRegionOffline(ctx, regionInfo);
656       }
657     });
658   }
659 
660   public boolean preBalance() throws IOException {
661     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
662       @Override
663       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
664           throws IOException {
665         oserver.preBalance(ctx);
666       }
667     });
668   }
669 
670   public void postBalance(final List<RegionPlan> plans) throws IOException {
671     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
672       @Override
673       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
674           throws IOException {
675         oserver.postBalance(ctx, plans);
676       }
677     });
678   }
679 
680   public boolean preBalanceSwitch(final boolean b) throws IOException {
681     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
682         new CoprocessorOperationWithResult<Boolean>() {
683       @Override
684       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
685           throws IOException {
686         setResult(oserver.preBalanceSwitch(ctx, getResult()));
687       }
688     });
689   }
690 
691   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
692       throws IOException {
693     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
694       @Override
695       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
696           throws IOException {
697         oserver.postBalanceSwitch(ctx, oldValue, newValue);
698       }
699     });
700   }
701 
702   public void preShutdown() 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.preShutdown(ctx);
708       }
709       @Override
710       public void postEnvCall(MasterEnvironment env) {
711         // invoke coprocessor stop method
712         shutdown(env);
713       }
714     });
715   }
716 
717   public void preStopMaster() throws IOException {
718     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
719       @Override
720       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
721           throws IOException {
722         oserver.preStopMaster(ctx);
723       }
724       @Override
725       public void postEnvCall(MasterEnvironment env) {
726         // invoke coprocessor stop method
727         shutdown(env);
728       }
729     });
730   }
731 
732   public void preMasterInitialization() 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.preMasterInitialization(ctx);
738       }
739     });
740   }
741 
742   public void postStartMaster() 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.postStartMaster(ctx);
748       }
749     });
750   }
751 
752   public void preSnapshot(final SnapshotDescription snapshot,
753       final HTableDescriptor hTableDescriptor) throws IOException {
754     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
755       @Override
756       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
757           throws IOException {
758         oserver.preSnapshot(ctx, snapshot, hTableDescriptor);
759       }
760     });
761   }
762 
763   public void postSnapshot(final SnapshotDescription snapshot,
764       final HTableDescriptor hTableDescriptor) 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.postSnapshot(ctx, snapshot, hTableDescriptor);
770       }
771     });
772   }
773 
774   public void preListSnapshot(final SnapshotDescription snapshot) throws IOException {
775     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
776       @Override
777       public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
778           throws IOException {
779         observer.preListSnapshot(ctx, snapshot);
780       }
781     });
782   }
783 
784   public void postListSnapshot(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.postListSnapshot(ctx, snapshot);
790       }
791     });
792   }
793 
794   public void preCloneSnapshot(final SnapshotDescription snapshot,
795       final HTableDescriptor hTableDescriptor) throws IOException {
796     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
797       @Override
798       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
799           throws IOException {
800         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
801       }
802     });
803   }
804 
805   public void postCloneSnapshot(final SnapshotDescription snapshot,
806       final HTableDescriptor hTableDescriptor) 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.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
812       }
813     });
814   }
815 
816   public void preRestoreSnapshot(final SnapshotDescription snapshot,
817       final HTableDescriptor hTableDescriptor) throws IOException {
818     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
819       @Override
820       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
821           throws IOException {
822         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
823       }
824     });
825   }
826 
827   public void postRestoreSnapshot(final SnapshotDescription snapshot,
828       final HTableDescriptor hTableDescriptor) throws IOException {
829     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
830       @Override
831       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
832           throws IOException {
833         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
834       }
835     });
836   }
837 
838   public void preDeleteSnapshot(final SnapshotDescription snapshot) 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.preDeleteSnapshot(ctx, snapshot);
844       }
845     });
846   }
847 
848   public void postDeleteSnapshot(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.postDeleteSnapshot(ctx, snapshot);
854       }
855     });
856   }
857 
858   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
859       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
860     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
861       @Override
862       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
863           throws IOException {
864         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
865       }
866     });
867   }
868 
869   public void postGetTableDescriptors(final List<TableName> tableNamesList,
870       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
871     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
872       @Override
873       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
874           throws IOException {
875         oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
876       }
877     });
878   }
879 
880   public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
881       final String regex) throws IOException {
882     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
883       @Override
884       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
885           throws IOException {
886         oserver.preGetTableNames(ctx, descriptors, regex);
887       }
888     });
889   }
890 
891   public void postGetTableNames(final List<HTableDescriptor> descriptors,
892       final String regex) throws IOException {
893     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
894       @Override
895       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
896           throws IOException {
897         oserver.postGetTableNames(ctx, descriptors, regex);
898       }
899     });
900   }
901 
902   public void preTableFlush(final TableName tableName) 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.preTableFlush(ctx, tableName);
908       }
909     });
910   }
911 
912   public void postTableFlush(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.postTableFlush(ctx, tableName);
918       }
919     });
920   }
921 
922   public void preSetUserQuota(final String user, final Quotas quotas) 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.preSetUserQuota(ctx, user, quotas);
928       }
929     });
930   }
931 
932   public void postSetUserQuota(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.postSetUserQuota(ctx, user, quotas);
938       }
939     });
940   }
941 
942   public void preSetUserQuota(final String user, final TableName table, final Quotas quotas)
943       throws IOException {
944     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
945       @Override
946       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
947           throws IOException {
948         oserver.preSetUserQuota(ctx, user, table, quotas);
949       }
950     });
951   }
952 
953   public void postSetUserQuota(final String user, final TableName table, final Quotas quotas)
954       throws IOException {
955     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
956       @Override
957       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
958           throws IOException {
959         oserver.postSetUserQuota(ctx, user, table, quotas);
960       }
961     });
962   }
963 
964   public void preSetUserQuota(final String user, final String namespace, final Quotas quotas)
965       throws IOException {
966     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
967       @Override
968       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
969           throws IOException {
970         oserver.preSetUserQuota(ctx, user, namespace, quotas);
971       }
972     });
973   }
974 
975   public void postSetUserQuota(final String user, final String namespace, final Quotas quotas)
976       throws IOException {
977     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
978       @Override
979       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
980           throws IOException {
981         oserver.postSetUserQuota(ctx, user, namespace, quotas);
982       }
983     });
984   }
985 
986   public void preSetTableQuota(final TableName table, final Quotas quotas) 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.preSetTableQuota(ctx, table, quotas);
992       }
993     });
994   }
995 
996   public void postSetTableQuota(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.postSetTableQuota(ctx, table, quotas);
1002       }
1003     });
1004   }
1005 
1006   public void preSetNamespaceQuota(final String namespace, 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.preSetNamespaceQuota(ctx, namespace, quotas);
1012       }
1013     });
1014   }
1015 
1016   public void postSetNamespaceQuota(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.postSetNamespaceQuota(ctx, namespace, quotas);
1022       }
1023     });
1024   }
1025 
1026   private static abstract class CoprocessorOperation
1027       extends ObserverContext<MasterCoprocessorEnvironment> {
1028     public CoprocessorOperation() {
1029     }
1030 
1031     public abstract void call(MasterObserver oserver,
1032         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
1033 
1034     public void postEnvCall(MasterEnvironment env) {
1035     }
1036   }
1037 
1038   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
1039     private T result = null;
1040     public void setResult(final T result) { this.result = result; }
1041     public T getResult() { return this.result; }
1042   }
1043 
1044   private <T> T execOperationWithResult(final T defaultValue,
1045       final CoprocessorOperationWithResult<T> ctx) throws IOException {
1046     if (ctx == null) return defaultValue;
1047     ctx.setResult(defaultValue);
1048     execOperation(ctx);
1049     return ctx.getResult();
1050   }
1051 
1052   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
1053     if (ctx == null) return false;
1054     boolean bypass = false;
1055     for (MasterEnvironment env: coprocessors) {
1056       if (env.getInstance() instanceof MasterObserver) {
1057         ctx.prepare(env);
1058         Thread currentThread = Thread.currentThread();
1059         ClassLoader cl = currentThread.getContextClassLoader();
1060         try {
1061           currentThread.setContextClassLoader(env.getClassLoader());
1062           ctx.call((MasterObserver)env.getInstance(), ctx);
1063         } catch (Throwable e) {
1064           handleCoprocessorThrowable(env, e);
1065         } finally {
1066           currentThread.setContextClassLoader(cl);
1067         }
1068         bypass |= ctx.shouldBypass();
1069         if (ctx.shouldComplete()) {
1070           break;
1071         }
1072       }
1073       ctx.postEnvCall(env);
1074     }
1075     return bypass;
1076   }
1077 }