From c323e7bfaa180dc9a9420ece2e191c21cd04b99a Mon Sep 17 00:00:00 2001 From: Balazs Meszaros Date: Wed, 23 May 2018 13:49:19 +0200 Subject: [PATCH] HBASE-20656 Validate pre-2.0 coprocessors against HBase 2.0+ Signed-off-by: Mike Drob --- .../hbase/checkstyle-suppressions.xml | 1 + .../hadoop/hbase/util/AbstractHBaseTool.java | 7 +- .../hbase/coprocessor/BulkLoadObserver.java | 8 +- .../tool/DataBlockEncodingValidator.java | 108 ++ .../hbase/tool/PreUpgradeValidator.java | 140 +- .../Branch1CoprocessorMethods.java | 1137 +++++++++++++++++ .../tool/coprocessor/CoprocessorMethod.java | 73 ++ .../tool/coprocessor/CoprocessorMethods.java | 66 + .../coprocessor/CoprocessorValidator.java | 247 ++++ .../coprocessor/CoprocessorViolation.java | 56 + .../CurrentCoprocessorMethods.java | 47 + .../coprocessor/CoprocessorValidatorTest.java | 177 +++ src/main/asciidoc/_chapters/ops_mgt.adoc | 34 +- 13 files changed, 2012 insertions(+), 89 deletions(-) create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/tool/DataBlockEncodingValidator.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/Branch1CoprocessorMethods.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethod.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethods.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidator.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorViolation.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CurrentCoprocessorMethods.java create mode 100644 hbase-server/src/test/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidatorTest.java diff --git a/hbase-checkstyle/src/main/resources/hbase/checkstyle-suppressions.xml b/hbase-checkstyle/src/main/resources/hbase/checkstyle-suppressions.xml index 9feb5558775..ad79163c555 100644 --- a/hbase-checkstyle/src/main/resources/hbase/checkstyle-suppressions.xml +++ b/hbase-checkstyle/src/main/resources/hbase/checkstyle-suppressions.xml @@ -38,4 +38,5 @@ + diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/AbstractHBaseTool.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/AbstractHBaseTool.java index 1dd720143ad..b4548844ea4 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/AbstractHBaseTool.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/AbstractHBaseTool.java @@ -22,7 +22,6 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; -import org.apache.hadoop.conf.Configurable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.util.Tool; @@ -46,9 +45,9 @@ import org.apache.hbase.thirdparty.org.apache.commons.cli.ParseException; * command-line argument parsing. */ @InterfaceAudience.Private -public abstract class AbstractHBaseTool implements Tool, Configurable { - protected static final int EXIT_SUCCESS = 0; - protected static final int EXIT_FAILURE = 1; +public abstract class AbstractHBaseTool implements Tool { + public static final int EXIT_SUCCESS = 0; + public static final int EXIT_FAILURE = 1; public static final String SHORT_HELP_OPTION = "h"; public static final String LONG_HELP_OPTION = "help"; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BulkLoadObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BulkLoadObserver.java index 25e6522018e..b69a7270371 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BulkLoadObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BulkLoadObserver.java @@ -21,13 +21,9 @@ package org.apache.hadoop.hbase.coprocessor; import java.io.IOException; -import org.apache.hadoop.hbase.Coprocessor; import org.apache.hadoop.hbase.HBaseInterfaceAudience; -import org.apache.hadoop.hbase.TableName; import org.apache.yetus.audience.InterfaceAudience; import org.apache.yetus.audience.InterfaceStability; -import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.PrepareBulkLoadRequest; -import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CleanupBulkLoadRequest; /** * Coprocessors implement this interface to observe and mediate bulk load operations. @@ -55,7 +51,7 @@ public interface BulkLoadObserver { * It can't bypass the default action, e.g., ctx.bypass() won't have effect. * If you need to get the region or table name, get it from the * ctx as follows: code>ctx.getEnvironment().getRegion(). Use - * getRegionInfo to fetch the encodedName and use getTabldDescriptor() to get the tableName. + * getRegionInfo to fetch the encodedName and use getTableDescriptor() to get the tableName. * @param ctx the environment to interact with the framework and master */ default void prePrepareBulkLoad(ObserverContext ctx) @@ -66,7 +62,7 @@ public interface BulkLoadObserver { * It can't bypass the default action, e.g., ctx.bypass() won't have effect. * If you need to get the region or table name, get it from the * ctx as follows: code>ctx.getEnvironment().getRegion(). Use - * getRegionInfo to fetch the encodedName and use getTabldDescriptor() to get the tableName. + * getRegionInfo to fetch the encodedName and use getTableDescriptor() to get the tableName. * @param ctx the environment to interact with the framework and master */ default void preCleanupBulkLoad(ObserverContext ctx) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/DataBlockEncodingValidator.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/DataBlockEncodingValidator.java new file mode 100644 index 00000000000..e72521b1225 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/DataBlockEncodingValidator.java @@ -0,0 +1,108 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.tool; + +import java.io.IOException; +import java.util.List; + +import org.apache.hadoop.hbase.HBaseInterfaceAudience; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; +import org.apache.hadoop.hbase.util.AbstractHBaseTool; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.yetus.audience.InterfaceAudience; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; + +@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) +public class DataBlockEncodingValidator extends AbstractHBaseTool { + + private static final Logger LOG = LoggerFactory.getLogger(DataBlockEncodingValidator.class); + private static final byte[] DATA_BLOCK_ENCODING = Bytes.toBytes("DATA_BLOCK_ENCODING"); + + /** + * Check DataBlockEncodings of column families are compatible. + * + * @return number of column families with incompatible DataBlockEncoding + * @throws IOException if a remote or network exception occurs + */ + private int validateDBE() throws IOException { + int incompatibilities = 0; + + LOG.info("Validating Data Block Encodings"); + + try (Connection connection = ConnectionFactory.createConnection(getConf()); + Admin admin = connection.getAdmin()) { + List tableDescriptors = admin.listTableDescriptors(); + String encoding = ""; + + for (TableDescriptor td : tableDescriptors) { + ColumnFamilyDescriptor[] columnFamilies = td.getColumnFamilies(); + for (ColumnFamilyDescriptor cfd : columnFamilies) { + try { + encoding = Bytes.toString(cfd.getValue(DATA_BLOCK_ENCODING)); + // IllegalArgumentException will be thrown if encoding is incompatible with 2.0 + DataBlockEncoding.valueOf(encoding); + } catch (IllegalArgumentException e) { + incompatibilities++; + LOG.warn("Incompatible DataBlockEncoding for table: {}, cf: {}, encoding: {}", + td.getTableName().getNameAsString(), cfd.getNameAsString(), encoding); + } + } + } + } + + if (incompatibilities > 0) { + LOG.warn("There are {} column families with incompatible Data Block Encodings. Do not " + + "upgrade until these encodings are converted to a supported one.", incompatibilities); + LOG.warn("Check http://hbase.apache.org/book.html#upgrade2.0.prefix-tree.removed " + + "for instructions."); + } else { + LOG.info("The used Data Block Encodings are compatible with HBase 2.0."); + } + + return incompatibilities; + } + + @Override + protected void printUsage() { + String header = "hbase " + PreUpgradeValidator.TOOL_NAME + " " + + PreUpgradeValidator.VALIDATE_DBE_NAME; + printUsage(header, null, ""); + } + + @Override + protected void addOptions() { + } + + @Override + protected void processOptions(CommandLine cmd) { + } + + @Override + protected int doWork() throws Exception { + return (validateDBE() == 0) ? EXIT_SUCCESS : EXIT_FAILURE; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/PreUpgradeValidator.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/PreUpgradeValidator.java index 6fe5a92b22a..a3c505ef60a 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/PreUpgradeValidator.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/PreUpgradeValidator.java @@ -18,111 +18,99 @@ */ package org.apache.hadoop.hbase.tool; -import java.io.IOException; -import java.util.List; +import java.util.Arrays; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseInterfaceAudience; -import org.apache.hadoop.hbase.client.Admin; -import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; -import org.apache.hadoop.hbase.client.Connection; -import org.apache.hadoop.hbase.client.ConnectionFactory; -import org.apache.hadoop.hbase.client.TableDescriptor; -import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; +import org.apache.hadoop.hbase.tool.coprocessor.CoprocessorValidator; import org.apache.hadoop.hbase.util.AbstractHBaseTool; -import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.util.Tool; +import org.apache.hadoop.util.ToolRunner; import org.apache.yetus.audience.InterfaceAudience; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; - /** * Tool for validating that cluster can be upgraded from HBase 1.x to 2.0 *

* Available validations: *

    - *
  • all: Run all pre-upgrade validations
  • - *
  • validateDBE: Check Data Block Encoding for column families
  • + *
  • validate-cp: Validates Co-processors compatibility
  • + *
  • validate-dbe: Check Data Block Encoding for column families
  • *
*

*/ @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) -public class PreUpgradeValidator extends AbstractHBaseTool { +public class PreUpgradeValidator implements Tool { + private static final Logger LOG = LoggerFactory + .getLogger(PreUpgradeValidator.class); - public static final String NAME = "pre-upgrade"; - private static final Logger LOG = LoggerFactory.getLogger(PreUpgradeValidator.class); - private static final byte[] DATA_BLOCK_ENCODING = Bytes.toBytes("DATA_BLOCK_ENCODING"); - private boolean validateAll; - private boolean validateDBE; + public static final String TOOL_NAME = "pre-upgrade"; + public static final String VALIDATE_CP_NAME = "validate-cp"; + public static final String VALIDATE_DBE_NAME = "validate-dbe"; - /** - * Check DataBlockEncodings of column families are compatible. - * - * @return number of column families with incompatible DataBlockEncoding - * @throws IOException if a remote or network exception occurs - */ - private int validateDBE() throws IOException { - int incompatibilities = 0; + private Configuration configuration; - LOG.info("Validating Data Block Encodings"); - - try (Connection connection = ConnectionFactory.createConnection(getConf()); - Admin admin = connection.getAdmin()) { - List tableDescriptors = admin.listTableDescriptors(); - String encoding = ""; - - for (TableDescriptor td : tableDescriptors) { - ColumnFamilyDescriptor[] columnFamilies = td.getColumnFamilies(); - for (ColumnFamilyDescriptor cfd : columnFamilies) { - try { - encoding = Bytes.toString(cfd.getValue(DATA_BLOCK_ENCODING)); - // IllegalArgumentException will be thrown if encoding is incompatible with 2.0 - DataBlockEncoding.valueOf(encoding); - } catch (IllegalArgumentException e) { - incompatibilities++; - LOG.warn("Incompatible DataBlockEncoding for table: {}, cf: {}, encoding: {}", - td.getTableName().getNameAsString(), cfd.getNameAsString(), encoding); - } - } - } - } - - if (incompatibilities > 0) { - LOG.warn("There are {} column families with incompatible Data Block Encodings. Do not " - + "upgrade until these encodings are converted to a supported one.", incompatibilities); - LOG.warn("Check http://hbase.apache.org/book.html#upgrade2.0.prefix-tree.removed " - + "for instructions."); - } else { - LOG.info("The used Data Block Encodings are compatible with HBase 2.0."); - } - return incompatibilities; + @Override + public Configuration getConf() { + return configuration; } @Override - protected void addOptions() { - addOptNoArg("all", "Run all pre-upgrade validations"); - addOptNoArg("validateDBE", "Validate DataBlockEncodings are compatible"); + public void setConf(Configuration conf) { + this.configuration = conf; + } + + private void printUsage() { + System.out.println("usage: hbase " + TOOL_NAME + " command ..."); + System.out.println("Available commands:"); + System.out.printf(" %-12s Validate co-processors are compatible with HBase%n", + VALIDATE_CP_NAME); + System.out.printf(" %-12s Validate DataBlockEncoding are compatible on the cluster%n", + VALIDATE_DBE_NAME); + System.out.println("For further information, please use command -h"); } @Override - protected void processOptions(CommandLine cmd) { - validateAll = cmd.hasOption("all"); - validateDBE = cmd.hasOption("validateDBE"); - } - - @Override - protected int doWork() throws Exception { - boolean validationFailed = false; - if (validateDBE || validateAll) { - if (validateDBE() > 0) { - validationFailed = true; - } + public int run(String[] args) throws Exception { + if (args.length == 0) { + printUsage(); + return AbstractHBaseTool.EXIT_FAILURE; } - return validationFailed ? 1 : 0; + Tool tool; + + switch (args[0]) { + case VALIDATE_CP_NAME: + tool = new CoprocessorValidator(); + break; + case VALIDATE_DBE_NAME: + tool = new DataBlockEncodingValidator(); + break; + case "-h": + printUsage(); + return AbstractHBaseTool.EXIT_FAILURE; + default: + System.err.println("Unknown command: " + args[0]); + printUsage(); + return AbstractHBaseTool.EXIT_FAILURE; + } + + tool.setConf(getConf()); + return tool.run(Arrays.copyOfRange(args, 1, args.length)); } public static void main(String[] args) { - new PreUpgradeValidator().doStaticMain(args); + int ret; + + try { + ret = ToolRunner.run(HBaseConfiguration.create(), new PreUpgradeValidator(), args); + } catch (Exception e) { + LOG.error("Error running command-line tool", e); + ret = AbstractHBaseTool.EXIT_FAILURE; + } + + System.exit(ret); } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/Branch1CoprocessorMethods.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/Branch1CoprocessorMethods.java new file mode 100644 index 00000000000..0f5d829de6b --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/Branch1CoprocessorMethods.java @@ -0,0 +1,1137 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.tool.coprocessor; + +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class Branch1CoprocessorMethods extends CoprocessorMethods { + public Branch1CoprocessorMethods() { + addMethods(); + } + + /* + * This list of methods was generated from HBase 1.4.4. + */ + private void addMethods() { + /* BulkLoadObserver */ + + addMethod("prePrepareBulkLoad", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.SecureBulkLoadProtos.PrepareBulkLoadRequest"); + + addMethod("preCleanupBulkLoad", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.SecureBulkLoadProtos.CleanupBulkLoadRequest"); + + /* EndpointObserver */ + + addMethod("postEndpointInvocation", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "com.google.protobuf.Service", + "java.lang.String", + "com.google.protobuf.Message", + "com.google.protobuf.Message.Builder"); + + addMethod("preEndpointInvocation", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "com.google.protobuf.Service", + "java.lang.String", + "com.google.protobuf.Message"); + + /* MasterObserver */ + + addMethod("preCreateTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HTableDescriptor", + "org.apache.hadoop.hbase.HRegionInfo[]"); + + addMethod("postCreateTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HTableDescriptor", + "org.apache.hadoop.hbase.HRegionInfo[]"); + + addMethod("preDeleteTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postDeleteTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preDeleteTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preMove", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.ServerName", + "org.apache.hadoop.hbase.ServerName"); + + addMethod("preCreateTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HTableDescriptor", + "org.apache.hadoop.hbase.HRegionInfo[]"); + + addMethod("postCreateTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HTableDescriptor", + "org.apache.hadoop.hbase.HRegionInfo[]"); + + addMethod("postMove", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.ServerName", + "org.apache.hadoop.hbase.ServerName"); + + addMethod("postDeleteTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preTruncateTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postTruncateTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preTruncateTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postTruncateTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preModifyTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("postModifyTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("preModifyTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("postModifyTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("preAddColumn", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("postAddColumn", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("preAddColumnHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("postAddColumnHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("preModifyColumn", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("postModifyColumn", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("preModifyColumnHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("postModifyColumnHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.HColumnDescriptor"); + + addMethod("preDeleteColumn", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "byte[]"); + + addMethod("postDeleteColumn", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "byte[]"); + + addMethod("preDeleteColumnHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "byte[]"); + + addMethod("postDeleteColumnHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "byte[]"); + + addMethod("preEnableTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postEnableTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preEnableTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postEnableTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preDisableTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postDisableTable", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preDisableTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postDisableTableHandler", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preAbortProcedure", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.procedure2.ProcedureExecutor", + "long"); + + addMethod("postAbortProcedure", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("preListProcedures", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postListProcedures", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List"); + + addMethod("preAssign", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo"); + + addMethod("postAssign", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo"); + + addMethod("preUnassign", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "boolean"); + + addMethod("postUnassign", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "boolean"); + + addMethod("preRegionOffline", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo"); + + addMethod("postRegionOffline", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo"); + + addMethod("preBalance", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postBalance", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List"); + + addMethod("preSetSplitOrMergeEnabled", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "boolean", + "org.apache.hadoop.hbase.client.Admin.MasterSwitchType"); + + addMethod("postSetSplitOrMergeEnabled", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "boolean", + "org.apache.hadoop.hbase.client.Admin.MasterSwitchType"); + + addMethod("preBalanceSwitch", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "boolean"); + + addMethod("postBalanceSwitch", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "boolean", + "boolean"); + + addMethod("preShutdown", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("preStopMaster", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postStartMaster", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("preMasterInitialization", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("preSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("postSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("preListSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription"); + + addMethod("postListSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription"); + + addMethod("preCloneSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("postCloneSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("preRestoreSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("postRestoreSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription", + "org.apache.hadoop.hbase.HTableDescriptor"); + + addMethod("preDeleteSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription"); + + addMethod("postDeleteSnapshot", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription"); + + addMethod("preGetTableDescriptors", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "java.util.List"); + + addMethod("preGetTableDescriptors", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "java.util.List", + "java.lang.String"); + + addMethod("postGetTableDescriptors", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "java.util.List", + "java.lang.String"); + + addMethod("postGetTableDescriptors", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List"); + + addMethod("preGetTableNames", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "java.lang.String"); + + addMethod("postGetTableNames", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "java.lang.String"); + + addMethod("preCreateNamespace", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.NamespaceDescriptor"); + + addMethod("postCreateNamespace", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.NamespaceDescriptor"); + + addMethod("preDeleteNamespace", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("postDeleteNamespace", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("preModifyNamespace", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.NamespaceDescriptor"); + + addMethod("postModifyNamespace", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.NamespaceDescriptor"); + + addMethod("preGetNamespaceDescriptor", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("postGetNamespaceDescriptor", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.NamespaceDescriptor"); + + addMethod("preListNamespaceDescriptors", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List"); + + addMethod("postListNamespaceDescriptors", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List"); + + addMethod("preTableFlush", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("postTableFlush", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName"); + + addMethod("preSetUserQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "java.lang.String", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("preSetUserQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("preSetUserQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("postSetUserQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "java.lang.String", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("postSetUserQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("postSetUserQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("preSetTableQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("postSetTableQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.TableName", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("preSetNamespaceQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("postSetNamespaceQuota", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas"); + + addMethod("preDispatchMerge", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.HRegionInfo"); + + addMethod("postDispatchMerge", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.HRegionInfo"); + + addMethod("preGetClusterStatus", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postGetClusterStatus", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.ClusterStatus"); + + addMethod("preClearDeadServers", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postClearDeadServers", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "java.util.List"); + + addMethod("preMoveServers", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set", + "java.lang.String"); + + addMethod("postMoveServers", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set", + "java.lang.String"); + + addMethod("preMoveTables", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set", + "java.lang.String"); + + addMethod("postMoveTables", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set", + "java.lang.String"); + + addMethod("preMoveServersAndTables", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set", + "java.util.Set", + "java.lang.String"); + + addMethod("postMoveServersAndTables", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set", + "java.util.Set", + "java.lang.String"); + + addMethod("preAddRSGroup", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("postAddRSGroup", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("preRemoveRSGroup", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("postRemoveRSGroup", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("preRemoveServers", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set"); + + addMethod("postRemoveServers", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.Set"); + + addMethod("preBalanceRSGroup", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String"); + + addMethod("postBalanceRSGroup", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.lang.String", + "boolean"); + + /* RegionObserver */ + + addMethod("preOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postLogReplay", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("preFlushScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.KeyValueScanner", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "long"); + + addMethod("preFlushScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.KeyValueScanner", + "org.apache.hadoop.hbase.regionserver.InternalScanner"); + + addMethod("preFlush", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.InternalScanner"); + + addMethod("preFlush", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postFlush", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.StoreFile"); + + addMethod("postFlush", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("preCompactSelection", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "java.util.List"); + + addMethod("preCompactSelection", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "java.util.List", + "org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest"); + + addMethod("postCompactSelection", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "com.google.common.collect.ImmutableList"); + + addMethod("postCompactSelection", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "com.google.common.collect.ImmutableList", + "org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest"); + + addMethod("preCompact", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "org.apache.hadoop.hbase.regionserver.ScanType"); + + addMethod("preCompact", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "org.apache.hadoop.hbase.regionserver.ScanType", + "org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest"); + + addMethod("preClose", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "boolean"); + + addMethod("preCompactScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "java.util.List", + "org.apache.hadoop.hbase.regionserver.ScanType", + "long", + "org.apache.hadoop.hbase.regionserver.InternalScanner"); + + addMethod("preCompactScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "java.util.List", + "org.apache.hadoop.hbase.regionserver.ScanType", + "long", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest", + "long"); + + addMethod("preCompactScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "java.util.List", + "org.apache.hadoop.hbase.regionserver.ScanType", + "long", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest"); + + addMethod("postCompact", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.StoreFile"); + + addMethod("postCompact", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.regionserver.StoreFile", + "org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest"); + + addMethod("preSplit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]"); + + addMethod("preSplit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postSplit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region"); + + addMethod("preSplitBeforePONR", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "java.util.List"); + + addMethod("preSplitAfterPONR", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("preRollBackSplit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postRollBackSplit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postCompleteSplit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postClose", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "boolean"); + + addMethod("preGetClosestRowBefore", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.client.Result"); + + addMethod("postGetClosestRowBefore", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.client.Result"); + + addMethod("preGetOp", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Get", + "java.util.List"); + + addMethod("postGetOp", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Get", + "java.util.List"); + + addMethod("preExists", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Get", + "boolean"); + + addMethod("postExists", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Get", + "boolean"); + + addMethod("prePut", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Put", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit", + "org.apache.hadoop.hbase.client.Durability"); + + addMethod("postPut", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Put", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit", + "org.apache.hadoop.hbase.client.Durability"); + + addMethod("preDelete", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Delete", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit", + "org.apache.hadoop.hbase.client.Durability"); + + addMethod("prePrepareTimeStampForDeleteVersion", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Mutation", + "org.apache.hadoop.hbase.Cell", + "byte[]", + "org.apache.hadoop.hbase.client.Get"); + + addMethod("postDelete", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Delete", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit", + "org.apache.hadoop.hbase.client.Durability"); + + addMethod("preBatchMutate", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress"); + + addMethod("postBatchMutate", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress"); + + addMethod("postStartRegionOperation", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region.Operation"); + + addMethod("postCloseRegionOperation", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region.Operation"); + + addMethod("postBatchMutateIndispensably", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress", + "boolean"); + + addMethod("preCheckAndPut", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.filter.CompareFilter.CompareOp", + "org.apache.hadoop.hbase.filter.ByteArrayComparable", + "org.apache.hadoop.hbase.client.Put", + "boolean"); + + addMethod("preCheckAndPutAfterRowLock", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.filter.CompareFilter.CompareOp", + "org.apache.hadoop.hbase.filter.ByteArrayComparable", + "org.apache.hadoop.hbase.client.Put", + "boolean"); + + addMethod("postCheckAndPut", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.filter.CompareFilter.CompareOp", + "org.apache.hadoop.hbase.filter.ByteArrayComparable", + "org.apache.hadoop.hbase.client.Put", + "boolean"); + + addMethod("preCheckAndDelete", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.filter.CompareFilter.CompareOp", + "org.apache.hadoop.hbase.filter.ByteArrayComparable", + "org.apache.hadoop.hbase.client.Delete", + "boolean"); + + addMethod("preCheckAndDeleteAfterRowLock", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.filter.CompareFilter.CompareOp", + "org.apache.hadoop.hbase.filter.ByteArrayComparable", + "org.apache.hadoop.hbase.client.Delete", + "boolean"); + + addMethod("postCheckAndDelete", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "org.apache.hadoop.hbase.filter.CompareFilter.CompareOp", + "org.apache.hadoop.hbase.filter.ByteArrayComparable", + "org.apache.hadoop.hbase.client.Delete", + "boolean"); + + addMethod("preIncrementColumnValue", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "long", + "boolean"); + + addMethod("postIncrementColumnValue", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "byte[]", + "byte[]", + "long", + "boolean", + "long"); + + addMethod("preAppend", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Append"); + + addMethod("preAppendAfterRowLock", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Append"); + + addMethod("postAppend", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Append", + "org.apache.hadoop.hbase.client.Result"); + + addMethod("preIncrement", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Increment"); + + addMethod("preIncrementAfterRowLock", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Increment"); + + addMethod("postIncrement", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Increment", + "org.apache.hadoop.hbase.client.Result"); + + addMethod("preScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Scan", + "org.apache.hadoop.hbase.regionserver.RegionScanner"); + + addMethod("preStoreScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Store", + "org.apache.hadoop.hbase.client.Scan", + "java.util.NavigableSet", + "org.apache.hadoop.hbase.regionserver.KeyValueScanner"); + + addMethod("postScannerOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.client.Scan", + "org.apache.hadoop.hbase.regionserver.RegionScanner"); + + addMethod("preScannerNext", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "java.util.List", + "int", + "boolean"); + + addMethod("postScannerNext", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "java.util.List", + "int", + "boolean"); + + addMethod("postScannerFilterRow", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.InternalScanner", + "byte[]", + "int", + "short", + "boolean"); + + addMethod("preScannerClose", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.InternalScanner"); + + addMethod("postScannerClose", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.InternalScanner"); + + addMethod("preWALRestore", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.regionserver.wal.HLogKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("preWALRestore", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.wal.WALKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("postWALRestore", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.regionserver.wal.HLogKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("postWALRestore", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.wal.WALKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("preBulkLoadHFile", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List"); + + addMethod("preCommitStoreFile", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "java.util.List"); + + addMethod("postCommitStoreFile", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "byte[]", + "org.apache.hadoop.fs.Path", + "org.apache.hadoop.fs.Path"); + + addMethod("postBulkLoadHFile", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "boolean"); + + addMethod("preStoreFileReaderOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.fs.FileSystem", + "org.apache.hadoop.fs.Path", + "org.apache.hadoop.hbase.io.FSDataInputStreamWrapper", + "long", + "org.apache.hadoop.hbase.io.hfile.CacheConfig", + "org.apache.hadoop.hbase.io.Reference", + "org.apache.hadoop.hbase.regionserver.StoreFile.Reader"); + + addMethod("postStoreFileReaderOpen", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.fs.FileSystem", + "org.apache.hadoop.fs.Path", + "org.apache.hadoop.hbase.io.FSDataInputStreamWrapper", + "long", + "org.apache.hadoop.hbase.io.hfile.CacheConfig", + "org.apache.hadoop.hbase.io.Reference", + "org.apache.hadoop.hbase.regionserver.StoreFile.Reader"); + + addMethod("postMutationBeforeWAL", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.coprocessor.RegionObserver.MutationType", + "org.apache.hadoop.hbase.client.Mutation", + "org.apache.hadoop.hbase.Cell", + "org.apache.hadoop.hbase.Cell"); + + addMethod("postInstantiateDeleteTracker", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.DeleteTracker"); + + /* RegionServerObserver */ + + addMethod("preMerge", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region"); + + addMethod("preStopRegionServer", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postMerge", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region"); + + addMethod("preMergeCommit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region", + "java.util.List"); + + addMethod("postMergeCommit", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region"); + + addMethod("preRollBackMerge", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region"); + + addMethod("postRollBackMerge", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.regionserver.Region", + "org.apache.hadoop.hbase.regionserver.Region"); + + addMethod("preRollWALWriterRequest", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postRollWALWriterRequest", + "org.apache.hadoop.hbase.coprocessor.ObserverContext"); + + addMethod("postCreateReplicationEndPoint", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.replication.ReplicationEndpoint"); + + addMethod("preReplicateLogEntries", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "org.apache.hadoop.hbase.CellScanner"); + + addMethod("postReplicateLogEntries", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "java.util.List", + "org.apache.hadoop.hbase.CellScanner"); + + /* WALObserver */ + + addMethod("preWALWrite", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.wal.WALKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("preWALWrite", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.regionserver.wal.HLogKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("postWALWrite", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.regionserver.wal.HLogKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("postWALWrite", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.hbase.HRegionInfo", + "org.apache.hadoop.hbase.wal.WALKey", + "org.apache.hadoop.hbase.regionserver.wal.WALEdit"); + + addMethod("preWALRoll", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.fs.Path", + "org.apache.hadoop.fs.Path"); + + addMethod("postWALRoll", + "org.apache.hadoop.hbase.coprocessor.ObserverContext", + "org.apache.hadoop.fs.Path", + "org.apache.hadoop.fs.Path"); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethod.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethod.java new file mode 100644 index 00000000000..60e38417135 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethod.java @@ -0,0 +1,73 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.tool.coprocessor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class CoprocessorMethod { + private final String name; + private final List parameters; + + public CoprocessorMethod(String name) { + this.name = name; + + parameters = new ArrayList<>(); + } + + public CoprocessorMethod withParameters(String ... parameters) { + for (String parameter : parameters) { + this.parameters.add(parameter); + } + + return this; + } + + public CoprocessorMethod withParameters(Class ... parameters) { + for (Class parameter : parameters) { + this.parameters.add(parameter.getCanonicalName()); + } + + return this; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (!(obj instanceof CoprocessorMethod)) { + return false; + } + + CoprocessorMethod other = (CoprocessorMethod)obj; + + return Objects.equals(name, other.name) && + Objects.equals(parameters, other.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(name, parameters); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethods.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethods.java new file mode 100644 index 00000000000..2e0c801b8aa --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorMethods.java @@ -0,0 +1,66 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.tool.coprocessor; + +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; + +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class CoprocessorMethods { + private final Set methods; + + public CoprocessorMethods() { + methods = new HashSet<>(); + } + + public void addMethod(String name, String ... parameters) { + CoprocessorMethod cpMethod = new CoprocessorMethod(name).withParameters(parameters); + methods.add(cpMethod); + } + + public void addMethod(String name, Class ... parameters) { + CoprocessorMethod cpMethod = new CoprocessorMethod(name).withParameters(parameters); + methods.add(cpMethod); + } + + public void addMethod(Method method) { + CoprocessorMethod cpMethod = new CoprocessorMethod(method.getName()) + .withParameters(method.getParameterTypes()); + methods.add(cpMethod); + } + + public boolean hasMethod(String name, String ... parameters) { + CoprocessorMethod method = new CoprocessorMethod(name).withParameters(parameters); + return methods.contains(method); + } + + public boolean hasMethod(String name, Class ... parameters) { + CoprocessorMethod method = new CoprocessorMethod(name).withParameters(parameters); + return methods.contains(method); + } + + public boolean hasMethod(Method method) { + CoprocessorMethod cpMethod = new CoprocessorMethod(method.getName()) + .withParameters(method.getParameterTypes()); + return methods.contains(cpMethod); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidator.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidator.java new file mode 100644 index 00000000000..c6d57236ae8 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidator.java @@ -0,0 +1,247 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.tool.coprocessor; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Collectors; + +import org.apache.hadoop.hbase.Coprocessor; +import org.apache.hadoop.hbase.HBaseInterfaceAudience; +import org.apache.hadoop.hbase.tool.PreUpgradeValidator; +import org.apache.hadoop.hbase.tool.coprocessor.CoprocessorViolation.Severity; +import org.apache.hadoop.hbase.util.AbstractHBaseTool; +import org.apache.yetus.audience.InterfaceAudience; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; +import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; +import org.apache.hbase.thirdparty.org.apache.commons.cli.ParseException; + +@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) +public class CoprocessorValidator extends AbstractHBaseTool { + private static final Logger LOG = LoggerFactory + .getLogger(CoprocessorValidator.class); + + private CoprocessorMethods branch1; + private CoprocessorMethods current; + + private boolean dieOnWarnings; + private boolean scan; + private List args; + + public CoprocessorValidator() { + branch1 = new Branch1CoprocessorMethods(); + current = new CurrentCoprocessorMethods(); + } + + /** + * This classloader implementation calls {@link #resolveClass(Class)} + * method for every loaded class. It means that some extra validation will + * take place + * according to JLS. + */ + private static final class ResolverUrlClassLoader extends URLClassLoader { + private ResolverUrlClassLoader(URL[] urls) { + super(urls, ResolverUrlClassLoader.class.getClassLoader()); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return loadClass(name, true); + } + } + + private ResolverUrlClassLoader createClassLoader(URL[] urls) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ResolverUrlClassLoader run() { + return new ResolverUrlClassLoader(urls); + } + }); + } + + private void validate(ClassLoader classLoader, String className, + List violations) { + LOG.debug("Validating class '{}'.", className); + + try { + Class clazz = classLoader.loadClass(className); + + for (Method method : clazz.getDeclaredMethods()) { + LOG.trace("Validating method '{}'.", method); + + if (branch1.hasMethod(method) && !current.hasMethod(method)) { + CoprocessorViolation violation = new CoprocessorViolation(Severity.WARNING, + "Method '" + method + "' was removed from new coprocessor API, " + + "so it won't be called by HBase."); + violations.add(violation); + } + } + } catch (ClassNotFoundException e) { + CoprocessorViolation violation = new CoprocessorViolation(Severity.ERROR, + "No such class '" + className + "'.", e); + violations.add(violation); + } catch (RuntimeException | Error e) { + CoprocessorViolation violation = new CoprocessorViolation(Severity.ERROR, + "Could not validate class '" + className + "'.", e); + violations.add(violation); + } + } + + public List validate(ClassLoader classLoader, List classNames) { + List violations = new ArrayList<>(); + + for (String className : classNames) { + validate(classLoader, className, violations); + } + + return violations; + } + + public List validate(List urls, List classNames) + throws IOException { + URL[] urlArray = new URL[urls.size()]; + urls.toArray(urlArray); + + try (ResolverUrlClassLoader classLoader = createClassLoader(urlArray)) { + return validate(classLoader, classNames); + } + } + + @VisibleForTesting + protected List getJarClasses(Path path) throws IOException { + try (JarFile jarFile = new JarFile(path.toFile())) { + return jarFile.stream() + .map(JarEntry::getName) + .filter((name) -> name.endsWith(".class")) + .map((name) -> name.substring(0, name.length() - 6).replace('/', '.')) + .collect(Collectors.toList()); + } + } + + @VisibleForTesting + protected List filterObservers(ClassLoader classLoader, + Iterable classNames) throws ClassNotFoundException { + List filteredClassNames = new ArrayList<>(); + + for (String className : classNames) { + LOG.debug("Scanning class '{}'.", className); + + Class clazz = classLoader.loadClass(className); + + if (Coprocessor.class.isAssignableFrom(clazz)) { + LOG.debug("Found coprocessor class '{}'.", className); + filteredClassNames.add(className); + } + } + + return filteredClassNames; + } + + @Override + protected void printUsage() { + String header = "hbase " + PreUpgradeValidator.TOOL_NAME + " " + + PreUpgradeValidator.VALIDATE_CP_NAME + " -scan|"; + printUsage(header, "Options:", ""); + } + + @Override + protected void addOptions() { + addOptNoArg("e", "Treat warnings as errors."); + addOptNoArg("scan", "Scan jar for observers."); + } + + @Override + protected void processOptions(CommandLine cmd) { + scan = cmd.hasOption("scan"); + dieOnWarnings = cmd.hasOption("e"); + args = cmd.getArgList(); + } + + @Override + protected int doWork() throws Exception { + if (args.size() < 1) { + System.err.println("Missing jar file."); + printUsage(); + return EXIT_FAILURE; + } + + String jar = args.get(0); + + if (args.size() == 1 && !scan) { + throw new ParseException("Missing classes or -scan option."); + } else if (args.size() > 1 && scan) { + throw new ParseException("Can't use classes with -scan option."); + } + + Path jarPath = Paths.get(jar); + URL[] urls = new URL[] { jarPath.toUri().toURL() }; + + List violations; + + try (ResolverUrlClassLoader classLoader = createClassLoader(urls)) { + List classNames; + + if (scan) { + List jarClassNames = getJarClasses(jarPath); + classNames = filterObservers(classLoader, jarClassNames); + } else { + classNames = args.subList(1, args.size()); + } + + violations = validate(classLoader, classNames); + } + + boolean error = false; + + for (CoprocessorViolation violation : violations) { + switch (violation.getSeverity()) { + case WARNING: + System.err.println("[WARNING] " + violation.getMessage()); + + if (dieOnWarnings) { + error = true; + } + + break; + case ERROR: + System.err.println("[ERROR] " + violation.getMessage()); + error = true; + + break; + } + } + + return (error) ? EXIT_FAILURE : EXIT_SUCCESS; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorViolation.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorViolation.java new file mode 100644 index 00000000000..c403c074179 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorViolation.java @@ -0,0 +1,56 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.tool.coprocessor; + +import org.apache.yetus.audience.InterfaceAudience; + +import org.apache.hbase.thirdparty.com.google.common.base.Throwables; + +@InterfaceAudience.Private +public class CoprocessorViolation { + public enum Severity { + WARNING, ERROR + } + + private final Severity severity; + private final String message; + + public CoprocessorViolation(Severity severity, String message) { + this(severity, message, null); + } + + public CoprocessorViolation(Severity severity, String message, Throwable t) { + this.severity = severity; + + if (t == null) { + this.message = message; + } else { + this.message = message + "\n" + Throwables.getStackTraceAsString(t); + } + } + + public Severity getSeverity() { + return severity; + } + + public String getMessage() { + return message; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CurrentCoprocessorMethods.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CurrentCoprocessorMethods.java new file mode 100644 index 00000000000..265cf5158ee --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/coprocessor/CurrentCoprocessorMethods.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.tool.coprocessor; + +import java.lang.reflect.Method; + +import org.apache.hadoop.hbase.coprocessor.BulkLoadObserver; +import org.apache.hadoop.hbase.coprocessor.EndpointObserver; +import org.apache.hadoop.hbase.coprocessor.MasterObserver; +import org.apache.hadoop.hbase.coprocessor.RegionObserver; +import org.apache.hadoop.hbase.coprocessor.RegionServerObserver; +import org.apache.hadoop.hbase.coprocessor.WALObserver; +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class CurrentCoprocessorMethods extends CoprocessorMethods { + public CurrentCoprocessorMethods() { + addMethods(BulkLoadObserver.class); + addMethods(EndpointObserver.class); + addMethods(MasterObserver.class); + addMethods(RegionObserver.class); + addMethods(RegionServerObserver.class); + addMethods(WALObserver.class); + } + + private void addMethods(Class clazz) { + for (Method method : clazz.getDeclaredMethods()) { + addMethod(method); + } + } +} diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidatorTest.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidatorTest.java new file mode 100644 index 00000000000..8926ff56ee4 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/coprocessor/CoprocessorValidatorTest.java @@ -0,0 +1,177 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.tool.coprocessor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.List; + +import org.apache.hadoop.hbase.Coprocessor; +import org.apache.hadoop.hbase.CoprocessorEnvironment; +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; +import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.tool.coprocessor.CoprocessorViolation.Severity; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.hbase.thirdparty.com.google.common.collect.Lists; + +@Category({ SmallTests.class }) +@SuppressWarnings("deprecation") +public class CoprocessorValidatorTest { + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(CoprocessorValidatorTest.class); + + private CoprocessorValidator validator; + + public CoprocessorValidatorTest() { + validator = new CoprocessorValidator(); + } + + private static ClassLoader getClassLoader() { + return CoprocessorValidatorTest.class.getClassLoader(); + } + + private static String getFullClassName(String className) { + return CoprocessorValidatorTest.class.getName() + "$" + className; + } + + @SuppressWarnings({"rawtypes", "unused"}) + private static class TestObserver implements Coprocessor { + @Override + public void start(CoprocessorEnvironment env) throws IOException { + } + + @Override + public void stop(CoprocessorEnvironment env) throws IOException { + } + } + + @Test + public void testFilterObservers() throws Exception { + String filterObservers = getFullClassName("TestObserver"); + List classNames = Lists.newArrayList( + filterObservers, getClass().getName()); + List filteredClassNames = validator.filterObservers(getClassLoader(), classNames); + + assertEquals(1, filteredClassNames.size()); + assertEquals(filterObservers, filteredClassNames.get(0)); + } + + private List validate(String className) { + ClassLoader classLoader = getClass().getClassLoader(); + return validate(classLoader, className); + } + + private List validate(ClassLoader classLoader, String className) { + List classNames = Lists.newArrayList(getClass().getName() + "$" + className); + return validator.validate(classLoader, classNames); + } + + /* + * In this test case, we are try to load a not-existent class. + */ + @Test + public void testNoSuchClass() throws IOException { + List violations = validate("NoSuchClass"); + assertEquals(1, violations.size()); + + CoprocessorViolation violation = violations.get(0); + assertEquals(Severity.ERROR, violation.getSeverity()); + assertTrue(violation.getMessage().contains( + "java.lang.ClassNotFoundException: " + + "org.apache.hadoop.hbase.tool.coprocessor.CoprocessorValidatorTest$NoSuchClass")); + } + + /* + * In this test case, we are validating MissingClass coprocessor, which + * references a missing class. With a special classloader, we prevent that + * class to be loaded at runtime. It simulates similar cases where a class + * is no more on our classpath. + * E.g. org.apache.hadoop.hbase.regionserver.wal.WALEdit was moved to + * org.apache.hadoop.hbase.wal, so class loading will fail on 2.0. + */ + private static class MissingClass { + } + + @SuppressWarnings("unused") + private static class MissingClassObserver { + public void method(MissingClass missingClass) { + } + } + + private static class MissingClassClassLoader extends ClassLoader { + public MissingClassClassLoader() { + super(getClassLoader()); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (name.equals(getFullClassName("MissingClass"))) { + throw new ClassNotFoundException(name); + } + + return super.findClass(name); + } + } + + @Test + public void testMissingClass() throws IOException { + MissingClassClassLoader missingClassClassLoader = new MissingClassClassLoader(); + List violations = validate(missingClassClassLoader, + "MissingClassObserver"); + assertEquals(1, violations.size()); + + CoprocessorViolation violation = violations.get(0); + assertEquals(Severity.ERROR, violation.getSeverity()); + assertTrue(violation.getMessage().contains( + "java.lang.ClassNotFoundException: " + + "org.apache.hadoop.hbase.tool.coprocessor.CoprocessorValidatorTest$MissingClass")); + } + + /* + * ObsoleteMethod coprocessor implements preCreateTable method which has + * HRegionInfo parameters. In our current implementation, we pass only + * RegionInfo parameters, so this method won't be called by HBase at all. + */ + @SuppressWarnings("unused") + private static class ObsoleteMethodObserver /* implements MasterObserver */ { + public void preCreateTable(ObserverContext ctx, + HTableDescriptor desc, HRegionInfo[] regions) throws IOException { + } + } + + @Test + public void testObsoleteMethod() throws IOException { + List violations = validate("ObsoleteMethodObserver"); + assertEquals(1, violations.size()); + + CoprocessorViolation violation = violations.get(0); + assertEquals(Severity.WARNING, violation.getSeverity()); + assertTrue(violation.getMessage().contains("was removed from new coprocessor API")); + } +} diff --git a/src/main/asciidoc/_chapters/ops_mgt.adoc b/src/main/asciidoc/_chapters/ops_mgt.adoc index 6fef714c916..60b749fba97 100644 --- a/src/main/asciidoc/_chapters/ops_mgt.adoc +++ b/src/main/asciidoc/_chapters/ops_mgt.adoc @@ -845,11 +845,39 @@ The LoadTestTool has received many updates in recent HBase releases, including s [[ops.pre-upgrade]] === Pre-Upgrade validator Pre-Upgrade validator tool can be used to check the cluster for known incompatibilities before upgrading from HBase 1 to HBase 2. -To run all the checks use the `-all` flag. [source, bash] ---- -$ bin/hbase pre-upgrade -all +$ bin/hbase pre-upgrade command ... +---- + +==== Coprocessor validation + +HBase supports co-processors for a long time, but the co-processor API can be changed between major releases. Co-processor validator tries to determine +whether the old co-processors are still compatible with the actual HBase version. + +[source, bash] +---- +$ bin/hbase pre-upgrade validate-cp -scan| +Options: + -e Treat warnings as errors. + -scan Scan jar for observers. +---- + +The first parameter of the tool is the `jar` file which holds the co-processor implementation. Further parameters can be `-scan` when the tool will +search the jar file for `Coprocessor` implementations or the `classes` can be explicitly given. + +The tool can report errors and warnings. Errors mean that HBase won't be able to load the coprocessor, because it is incompatible with the current version +of HBase. Warnings mean that the co-processors can be loaded, but they won't work as expected. If `-e` option is given, then the tool will also fail +for warnings. + +Please note that this tool cannot validate every aspect of jar files, it just does some static checks. + +For example: + +[source, bash] +---- +$ bin/hbase pre-upgrade validate-cp my-coprocessor.jar MyMasterObserver MyRegionObserver ---- ==== DataBlockEncoding validation @@ -858,7 +886,7 @@ To verify that none of the column families are using incompatible Data Block Enc [source, bash] ---- -$ bin/hbase pre-upgrade -validateDBE +$ bin/hbase pre-upgrade validate-dbe ---- This check validates all column families and print out any incompatibilities.