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