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 columnFamily)
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, columnFamily);
384         oserver.preAddColumnFamily(ctx, tableName, columnFamily);
385       }
386     });
387   }
388 
389   public void postAddColumn(final TableName tableName, final HColumnDescriptor columnFamily)
390       throws IOException {
391     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
392       @Override
393       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
394           throws IOException {
395         oserver.postAddColumn(ctx, tableName, columnFamily);
396         oserver.postAddColumnFamily(ctx, tableName, columnFamily);
397       }
398     });
399   }
400 
401   public boolean preAddColumnHandler(final TableName tableName,
402                                      final HColumnDescriptor columnFamily)
403       throws IOException {
404     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
405       @Override
406       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
407           throws IOException {
408         oserver.preAddColumnHandler(ctx, tableName, columnFamily);
409         oserver.preAddColumnFamilyHandler(ctx, tableName, columnFamily);
410       }
411     });
412   }
413 
414   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor columnFamily)
415       throws IOException {
416     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
417       @Override
418       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
419           throws IOException {
420         oserver.postAddColumnHandler(ctx, tableName, columnFamily);
421         oserver.postAddColumnFamilyHandler(ctx, tableName, columnFamily);
422       }
423     });
424   }
425 
426   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor columnFamily)
427       throws IOException {
428     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
429       @Override
430       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
431           throws IOException {
432         oserver.preModifyColumn(ctx, tableName, columnFamily);
433         oserver.preModifyColumnFamily(ctx, tableName, columnFamily);
434       }
435     });
436   }
437 
438   public void postModifyColumn(final TableName tableName, final HColumnDescriptor columnFamily)
439       throws IOException {
440     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
441       @Override
442       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
443           throws IOException {
444         oserver.postModifyColumn(ctx, tableName, columnFamily);
445         oserver.postModifyColumnFamily(ctx, tableName, columnFamily);
446       }
447     });
448   }
449 
450   public boolean preModifyColumnHandler(final TableName tableName,
451       final HColumnDescriptor columnFamily) throws IOException {
452     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
453       @Override
454       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
455           throws IOException {
456         oserver.preModifyColumnHandler(ctx, tableName, columnFamily);
457         oserver.preModifyColumnFamilyHandler(ctx, tableName, columnFamily);
458       }
459     });
460   }
461 
462   public void postModifyColumnHandler(final TableName tableName,
463       final HColumnDescriptor columnFamily) throws IOException {
464     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
465       @Override
466       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
467           throws IOException {
468         oserver.postModifyColumnHandler(ctx, tableName, columnFamily);
469         oserver.postModifyColumnFamilyHandler(ctx, tableName, columnFamily);
470       }
471     });
472   }
473 
474   public boolean preDeleteColumn(final TableName tableName, final byte[] columnFamily)
475       throws IOException {
476     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
477       @Override
478       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
479           throws IOException {
480         oserver.preDeleteColumn(ctx, tableName, columnFamily);
481         oserver.preDeleteColumnFamily(ctx, tableName, columnFamily);
482       }
483     });
484   }
485 
486   public void postDeleteColumn(final TableName tableName, final byte[] columnFamily)
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.postDeleteColumn(ctx, tableName, columnFamily);
493         oserver.postDeleteColumnFamily(ctx, tableName, columnFamily);
494       }
495     });
496   }
497 
498   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] columnFamily)
499       throws IOException {
500     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
501       @Override
502       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
503           throws IOException {
504         oserver.preDeleteColumnHandler(ctx, tableName, columnFamily);
505         oserver.preDeleteColumnFamilyHandler(ctx, tableName, columnFamily);
506       }
507     });
508   }
509 
510   public void postDeleteColumnHandler(final TableName tableName, final byte[] columnFamily)
511       throws IOException {
512     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
513       @Override
514       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
515           throws IOException {
516         oserver.postDeleteColumnHandler(ctx, tableName, columnFamily);
517         oserver.postDeleteColumnFamilyHandler(ctx, tableName, columnFamily);
518       }
519     });
520   }
521 
522   public void preEnableTable(final TableName tableName) throws IOException {
523     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
524       @Override
525       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
526           throws IOException {
527         oserver.preEnableTable(ctx, tableName);
528       }
529     });
530   }
531 
532   public void postEnableTable(final TableName tableName) throws IOException {
533     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
534       @Override
535       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
536           throws IOException {
537         oserver.postEnableTable(ctx, tableName);
538       }
539     });
540   }
541 
542   public void preEnableTableHandler(final TableName tableName) throws IOException {
543     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
544       @Override
545       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
546           throws IOException {
547         oserver.preEnableTableHandler(ctx, tableName);
548       }
549     });
550   }
551 
552   public void postEnableTableHandler(final TableName tableName) throws IOException {
553     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
554       @Override
555       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
556           throws IOException {
557         oserver.postEnableTableHandler(ctx, tableName);
558       }
559     });
560   }
561 
562   public void preDisableTable(final TableName tableName) 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.preDisableTable(ctx, tableName);
568       }
569     });
570   }
571 
572   public void postDisableTable(final TableName tableName) throws IOException {
573     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
574       @Override
575       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
576           throws IOException {
577         oserver.postDisableTable(ctx, tableName);
578       }
579     });
580   }
581 
582   public void preDisableTableHandler(final TableName tableName) 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.preDisableTableHandler(ctx, tableName);
588       }
589     });
590   }
591 
592   public void postDisableTableHandler(final TableName tableName) throws IOException {
593     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
594       @Override
595       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
596           throws IOException {
597         oserver.postDisableTableHandler(ctx, tableName);
598       }
599     });
600   }
601 
602   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
603       final ServerName destServer) throws IOException {
604     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
605       @Override
606       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
607           throws IOException {
608         oserver.preMove(ctx, region, srcServer, destServer);
609       }
610     });
611   }
612 
613   public void postMove(final HRegionInfo region, final ServerName srcServer,
614       final ServerName destServer) throws IOException {
615     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
616       @Override
617       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
618           throws IOException {
619         oserver.postMove(ctx, region, srcServer, destServer);
620       }
621     });
622   }
623 
624   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
625     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
626       @Override
627       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
628           throws IOException {
629         oserver.preAssign(ctx, regionInfo);
630       }
631     });
632   }
633 
634   public void postAssign(final HRegionInfo regionInfo) throws IOException {
635     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
636       @Override
637       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
638           throws IOException {
639         oserver.postAssign(ctx, regionInfo);
640       }
641     });
642   }
643 
644   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
645       throws IOException {
646     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
647       @Override
648       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
649           throws IOException {
650         oserver.preUnassign(ctx, regionInfo, force);
651       }
652     });
653   }
654 
655   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
656     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
657       @Override
658       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
659           throws IOException {
660         oserver.postUnassign(ctx, regionInfo, force);
661       }
662     });
663   }
664 
665   public void preRegionOffline(final HRegionInfo regionInfo) 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.preRegionOffline(ctx, regionInfo);
671       }
672     });
673   }
674 
675   public void postRegionOffline(final HRegionInfo regionInfo) 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.postRegionOffline(ctx, regionInfo);
681       }
682     });
683   }
684 
685   public boolean preBalance() throws IOException {
686     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
687       @Override
688       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
689           throws IOException {
690         oserver.preBalance(ctx);
691       }
692     });
693   }
694 
695   public void postBalance(final List<RegionPlan> plans) throws IOException {
696     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
697       @Override
698       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
699           throws IOException {
700         oserver.postBalance(ctx, plans);
701       }
702     });
703   }
704 
705   public boolean preBalanceSwitch(final boolean b) throws IOException {
706     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
707         new CoprocessorOperationWithResult<Boolean>() {
708       @Override
709       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
710           throws IOException {
711         setResult(oserver.preBalanceSwitch(ctx, getResult()));
712       }
713     });
714   }
715 
716   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
717       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.postBalanceSwitch(ctx, oldValue, newValue);
723       }
724     });
725   }
726 
727   public void preShutdown() 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.preShutdown(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 preStopMaster() 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.preStopMaster(ctx);
748       }
749       @Override
750       public void postEnvCall(MasterEnvironment env) {
751         // invoke coprocessor stop method
752         shutdown(env);
753       }
754     });
755   }
756 
757   public void preMasterInitialization() throws IOException {
758     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
759       @Override
760       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
761           throws IOException {
762         oserver.preMasterInitialization(ctx);
763       }
764     });
765   }
766 
767   public void postStartMaster() throws IOException {
768     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
769       @Override
770       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
771           throws IOException {
772         oserver.postStartMaster(ctx);
773       }
774     });
775   }
776 
777   public void preSnapshot(final SnapshotDescription snapshot,
778       final HTableDescriptor hTableDescriptor) throws IOException {
779     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
780       @Override
781       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
782           throws IOException {
783         oserver.preSnapshot(ctx, snapshot, hTableDescriptor);
784       }
785     });
786   }
787 
788   public void postSnapshot(final SnapshotDescription snapshot,
789       final HTableDescriptor hTableDescriptor) throws IOException {
790     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
791       @Override
792       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
793           throws IOException {
794         oserver.postSnapshot(ctx, snapshot, hTableDescriptor);
795       }
796     });
797   }
798 
799   public void preListSnapshot(final SnapshotDescription snapshot) throws IOException {
800     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
801       @Override
802       public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
803           throws IOException {
804         observer.preListSnapshot(ctx, snapshot);
805       }
806     });
807   }
808 
809   public void postListSnapshot(final SnapshotDescription snapshot) throws IOException {
810     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
811       @Override
812       public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
813           throws IOException {
814         observer.postListSnapshot(ctx, snapshot);
815       }
816     });
817   }
818 
819   public void preCloneSnapshot(final SnapshotDescription snapshot,
820       final HTableDescriptor hTableDescriptor) throws IOException {
821     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
822       @Override
823       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
824           throws IOException {
825         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
826       }
827     });
828   }
829 
830   public void postCloneSnapshot(final SnapshotDescription snapshot,
831       final HTableDescriptor hTableDescriptor) throws IOException {
832     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
833       @Override
834       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
835           throws IOException {
836         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
837       }
838     });
839   }
840 
841   public void preRestoreSnapshot(final SnapshotDescription snapshot,
842       final HTableDescriptor hTableDescriptor) throws IOException {
843     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
844       @Override
845       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
846           throws IOException {
847         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
848       }
849     });
850   }
851 
852   public void postRestoreSnapshot(final SnapshotDescription snapshot,
853       final HTableDescriptor hTableDescriptor) throws IOException {
854     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
855       @Override
856       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
857           throws IOException {
858         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
859       }
860     });
861   }
862 
863   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
864     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
865       @Override
866       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
867           throws IOException {
868         oserver.preDeleteSnapshot(ctx, snapshot);
869       }
870     });
871   }
872 
873   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
874     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
875       @Override
876       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
877           throws IOException {
878         oserver.postDeleteSnapshot(ctx, snapshot);
879       }
880     });
881   }
882 
883   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
884       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
885     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
886       @Override
887       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
888           throws IOException {
889         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
890       }
891     });
892   }
893 
894   public void postGetTableDescriptors(final List<TableName> tableNamesList,
895       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
896     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
897       @Override
898       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
899           throws IOException {
900         oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
901       }
902     });
903   }
904 
905   public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
906       final String regex) throws IOException {
907     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
908       @Override
909       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
910           throws IOException {
911         oserver.preGetTableNames(ctx, descriptors, regex);
912       }
913     });
914   }
915 
916   public void postGetTableNames(final List<HTableDescriptor> descriptors,
917       final String regex) throws IOException {
918     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
919       @Override
920       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
921           throws IOException {
922         oserver.postGetTableNames(ctx, descriptors, regex);
923       }
924     });
925   }
926 
927   public void preTableFlush(final TableName tableName) throws IOException {
928     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
929       @Override
930       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
931           throws IOException {
932         oserver.preTableFlush(ctx, tableName);
933       }
934     });
935   }
936 
937   public void postTableFlush(final TableName tableName) throws IOException {
938     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
939       @Override
940       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
941           throws IOException {
942         oserver.postTableFlush(ctx, tableName);
943       }
944     });
945   }
946 
947   public void preSetUserQuota(final String user, final Quotas quotas) throws IOException {
948     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
949       @Override
950       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
951           throws IOException {
952         oserver.preSetUserQuota(ctx, user, quotas);
953       }
954     });
955   }
956 
957   public void postSetUserQuota(final String user, final Quotas quotas) throws IOException {
958     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
959       @Override
960       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
961           throws IOException {
962         oserver.postSetUserQuota(ctx, user, quotas);
963       }
964     });
965   }
966 
967   public void preSetUserQuota(final String user, final TableName table, final Quotas quotas)
968       throws IOException {
969     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
970       @Override
971       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
972           throws IOException {
973         oserver.preSetUserQuota(ctx, user, table, quotas);
974       }
975     });
976   }
977 
978   public void postSetUserQuota(final String user, final TableName table, final Quotas quotas)
979       throws IOException {
980     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
981       @Override
982       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
983           throws IOException {
984         oserver.postSetUserQuota(ctx, user, table, quotas);
985       }
986     });
987   }
988 
989   public void preSetUserQuota(final String user, final String namespace, final Quotas quotas)
990       throws IOException {
991     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
992       @Override
993       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
994           throws IOException {
995         oserver.preSetUserQuota(ctx, user, namespace, quotas);
996       }
997     });
998   }
999 
1000   public void postSetUserQuota(final String user, final String namespace, final Quotas quotas)
1001       throws IOException {
1002     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1003       @Override
1004       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1005           throws IOException {
1006         oserver.postSetUserQuota(ctx, user, namespace, quotas);
1007       }
1008     });
1009   }
1010 
1011   public void preSetTableQuota(final TableName table, final Quotas quotas) throws IOException {
1012     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1013       @Override
1014       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1015           throws IOException {
1016         oserver.preSetTableQuota(ctx, table, quotas);
1017       }
1018     });
1019   }
1020 
1021   public void postSetTableQuota(final TableName table, final Quotas quotas) throws IOException {
1022     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1023       @Override
1024       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1025           throws IOException {
1026         oserver.postSetTableQuota(ctx, table, quotas);
1027       }
1028     });
1029   }
1030 
1031   public void preSetNamespaceQuota(final String namespace, final Quotas quotas) throws IOException {
1032     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1033       @Override
1034       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1035           throws IOException {
1036         oserver.preSetNamespaceQuota(ctx, namespace, quotas);
1037       }
1038     });
1039   }
1040 
1041   public void postSetNamespaceQuota(final String namespace, final Quotas quotas) throws IOException{
1042     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1043       @Override
1044       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1045           throws IOException {
1046         oserver.postSetNamespaceQuota(ctx, namespace, quotas);
1047       }
1048     });
1049   }
1050 
1051   private static abstract class CoprocessorOperation
1052       extends ObserverContext<MasterCoprocessorEnvironment> {
1053     public CoprocessorOperation() {
1054     }
1055 
1056     public abstract void call(MasterObserver oserver,
1057         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
1058 
1059     public void postEnvCall(MasterEnvironment env) {
1060     }
1061   }
1062 
1063   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
1064     private T result = null;
1065     public void setResult(final T result) { this.result = result; }
1066     public T getResult() { return this.result; }
1067   }
1068 
1069   private <T> T execOperationWithResult(final T defaultValue,
1070       final CoprocessorOperationWithResult<T> ctx) throws IOException {
1071     if (ctx == null) return defaultValue;
1072     ctx.setResult(defaultValue);
1073     execOperation(ctx);
1074     return ctx.getResult();
1075   }
1076 
1077   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
1078     if (ctx == null) return false;
1079     boolean bypass = false;
1080     for (MasterEnvironment env: coprocessors) {
1081       if (env.getInstance() instanceof MasterObserver) {
1082         ctx.prepare(env);
1083         Thread currentThread = Thread.currentThread();
1084         ClassLoader cl = currentThread.getContextClassLoader();
1085         try {
1086           currentThread.setContextClassLoader(env.getClassLoader());
1087           ctx.call((MasterObserver)env.getInstance(), ctx);
1088         } catch (Throwable e) {
1089           handleCoprocessorThrowable(env, e);
1090         } finally {
1091           currentThread.setContextClassLoader(cl);
1092         }
1093         bypass |= ctx.shouldBypass();
1094         if (ctx.shouldComplete()) {
1095           break;
1096         }
1097       }
1098       ctx.postEnvCall(env);
1099     }
1100     return bypass;
1101   }
1102 }