diff --git a/bin/hbase b/bin/hbase index b371ffc2ec0..5087e599342 100755 --- a/bin/hbase +++ b/bin/hbase @@ -103,6 +103,7 @@ if [ $# = 0 ]; then echo " ltt Run LoadTestTool" echo " canary Run the Canary tool" echo " version Print the version" + echo " regionsplitter Run RegionSplitter tool" echo " CLASSNAME Run the class named CLASSNAME" exit 1 fi @@ -456,6 +457,8 @@ elif [ "$COMMAND" = "canary" ] ; then HBASE_OPTS="$HBASE_OPTS $HBASE_CANARY_OPTS" elif [ "$COMMAND" = "version" ] ; then CLASS='org.apache.hadoop.hbase.util.VersionInfo' +elif [ "$COMMAND" = "regionsplitter" ] ; then + CLASS='org.apache.hadoop.hbase.util.RegionSplitter' else CLASS=$COMMAND fi 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 d2d8dac4311..1dd720143ad 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 @@ -137,7 +137,7 @@ public abstract class AbstractHBaseTool implements Tool, Configurable { } String[] remainingArgs = new String[argsList.size()]; argsList.toArray(remainingArgs); - cmd = new DefaultParser().parse(options, remainingArgs); + cmd = newParser().parse(options, remainingArgs); } catch (MissingOptionException e) { LOG.error(e.getMessage()); LOG.error("Use -h or --help for usage instructions."); @@ -160,6 +160,16 @@ public abstract class AbstractHBaseTool implements Tool, Configurable { return ret; } + /** + * Create the parser to use for parsing and validating the command line. Since commons-cli lacks + * the capability to validate arbitrary combination of options, it may be helpful to bake custom + * logic into a specialized parser implementation. See LoadTestTool for examples. + * @return a new parser specific to the current tool + */ + protected CommandLineParser newParser() { + return new DefaultParser(); + } + private boolean isHelpCommand(String[] args) throws ParseException { Options helpOption = new Options().addOption(HELP_OPTION); // this parses the command line but doesn't throw an exception on unknown options diff --git a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java index 51b2cf3ad1f..0f7c5c00469 100644 --- a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java +++ b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java @@ -58,7 +58,14 @@ import org.apache.hadoop.hbase.security.access.Permission; import org.apache.hadoop.hbase.util.test.LoadTestDataGenerator; import org.apache.hadoop.hbase.util.test.LoadTestDataGeneratorWithACL; import org.apache.hadoop.util.ToolRunner; + +import org.apache.hbase.thirdparty.org.apache.commons.cli.AlreadySelectedException; import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; +import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLineParser; +import org.apache.hbase.thirdparty.org.apache.commons.cli.DefaultParser; +import org.apache.hbase.thirdparty.org.apache.commons.cli.MissingOptionException; +import org.apache.hbase.thirdparty.org.apache.commons.cli.Options; +import org.apache.hbase.thirdparty.org.apache.commons.cli.ParseException; /** * A command-line utility that reads, writes, and verifies data. Unlike @@ -358,6 +365,40 @@ public class LoadTestTool extends AbstractHBaseTool { addOptWithArg(OPT_MOB_THRESHOLD, OPT_MOB_THRESHOLD_USAGE); } + @Override + protected CommandLineParser newParser() { + // Commons-CLI lacks the capability to handle combinations of options, so we do it ourselves + // Validate in parse() to get helpful error messages instead of exploding in processOptions() + return new DefaultParser() { + @Override + public CommandLine parse(Options opts, String[] args, Properties props, boolean stop) + throws ParseException { + CommandLine cl = super.parse(opts, args, props, stop); + + boolean isReadWriteUpdate = cmd.hasOption(OPT_READ) + || cmd.hasOption(OPT_WRITE) + || cmd.hasOption(OPT_UPDATE); + boolean isInitOnly = cmd.hasOption(OPT_INIT_ONLY); + + if (!isInitOnly && !isReadWriteUpdate) { + throw new MissingOptionException("Must specify either -" + OPT_INIT_ONLY + + " or at least one of -" + OPT_READ + ", -" + OPT_WRITE + ", -" + OPT_UPDATE); + } + + if (isInitOnly && isReadWriteUpdate) { + throw new AlreadySelectedException(OPT_INIT_ONLY + " cannot be specified with any of -" + + OPT_READ + ", -" + OPT_WRITE + ", -" + OPT_UPDATE); + } + + if (isReadWriteUpdate && !cmd.hasOption(OPT_NUM_KEYS)) { + throw new MissingOptionException(OPT_NUM_KEYS + " must be specified in read/write mode."); + } + + return cl; + } + }; + } + @Override protected void processOptions(CommandLine cmd) { this.cmd = cmd; @@ -381,21 +422,7 @@ public class LoadTestTool extends AbstractHBaseTool { isInitOnly = cmd.hasOption(OPT_INIT_ONLY); deferredLogFlush = cmd.hasOption(OPT_DEFERRED_LOG_FLUSH); - if (!isWrite && !isRead && !isUpdate && !isInitOnly) { - throw new IllegalArgumentException("Either -" + OPT_WRITE + " or " + - "-" + OPT_UPDATE + " or -" + OPT_READ + " has to be specified"); - } - - if (isInitOnly && (isRead || isWrite || isUpdate)) { - throw new IllegalArgumentException(OPT_INIT_ONLY + " cannot be specified with" - + " either -" + OPT_WRITE + " or -" + OPT_UPDATE + " or -" + OPT_READ); - } - if (!isInitOnly) { - if (!cmd.hasOption(OPT_NUM_KEYS)) { - throw new IllegalArgumentException(OPT_NUM_KEYS + " must be specified in " - + "read or write mode"); - } startKey = parseLong(cmd.getOptionValue(OPT_START_KEY, String.valueOf(DEFAULT_START_KEY)), 0, Long.MAX_VALUE); long numKeys = parseLong(cmd.getOptionValue(OPT_NUM_KEYS), 1, diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java index 31208c1361a..8875862f1d9 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java @@ -837,9 +837,8 @@ public final class Canary implements Tool { } private void printUsageAndExit() { - System.err.printf( - "Usage: hbase %s [opts] [table1 [table2]...] | [regionserver1 [regionserver2]..]%n", - getClass().getName()); + System.err.println( + "Usage: hbase canary [opts] [table1 [table2]...] | [regionserver1 [regionserver2]..]"); System.err.println(" where [opts] are:"); System.err.println(" -help Show this help and exit."); System.err.println(" -regionserver replace the table argument to regionserver,"); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java index ff7e2552386..1b586348075 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java @@ -331,7 +331,7 @@ public class RegionSplitter { opt.addOption(null, "lastrow", true, "Last Row in Table for Split Algorithm"); opt.addOption(null, "risky", false, - "Skip verification steps to complete quickly." + "Skip verification steps to complete quickly. " + "STRONGLY DISCOURAGED for production systems. "); CommandLine cmd = new GnuParser().parse(opt, args); @@ -356,8 +356,8 @@ public class RegionSplitter { boolean oneOperOnly = createTable ^ rollingSplit; if (2 != cmd.getArgList().size() || !oneOperOnly || cmd.hasOption("h")) { - new HelpFormatter().printHelp("RegionSplitter