From 7307445eff4ad6f78196d7c18c25b691b6b37c7c Mon Sep 17 00:00:00 2001 From: Clara Xiong Date: Wed, 17 Jun 2020 22:17:44 -0700 Subject: [PATCH 1/6] HBASE-24587 hbck2 command should accept one or more files containing a list of region names/table names/namespaces --- hbase-hbck2/README.md | 6 +- .../src/main/java/org/apache/hbase/HBCK2.java | 69 +++++++++++-------- .../test/java/org/apache/hbase/TestHBCK2.java | 62 ++++++++++++----- 3 files changed, 89 insertions(+), 48 deletions(-) diff --git a/hbase-hbck2/README.md b/hbase-hbck2/README.md index c8ebb79579..04961c8584 100644 --- a/hbase-hbck2/README.md +++ b/hbase-hbck2/README.md @@ -137,12 +137,13 @@ Command: Returns the pid(s) of the created AssignProcedure(s) or -1 if none. If -i or --inputFiles is specified, pass one or more input file names. Each file contains encoded region names, one per line. For example: - $ HBCK2 assigns -i fileName1 fileName2 + $ HBCK2 -i assigns fileName1 fileName2 bypass [OPTIONS] ... Options: -o,--override override if procedure is running/stuck -r,--recursive bypass parent and its children. SLOW! EXPENSIVE! -w,--lockWait milliseconds to wait before giving up; default=1 + -i, --inputFile take one or more files to read the args from Pass one (or more) procedure 'pid's to skip to procedure finish. Parent of bypassed procedure will also be skipped to the finish. Entities will be left in an inconsistent state and will require manual fixup. May @@ -300,6 +301,9 @@ Command: of what a userspace encoded region name looks like. For example: $ HBCK2 unassign 1588230740 de00010733901a05f5a2a3a382e27dd4 Returns the pid(s) of the created UnassignProcedure(s) or -1 if none. + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains encoded region names, one per line. For example: + $ HBCK2 -i unassigns fileName1 fileName2 SEE ALSO, org.apache.hbase.hbck1.OfflineMetaRepair, the offline hbase:meta tool. See the HBCK2 README for how to use. diff --git a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java index 84dc8341e9..2021af526b 100644 --- a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java +++ b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java @@ -128,6 +128,7 @@ public class HBCK2 extends Configured implements org.apache.hadoop.util.Tool { private Configuration conf; static final String [] MINIMUM_HBCK2_VERSION = {"2.0.3", "2.1.1", "2.2.0", "3.0.0"}; private boolean skipCheck = false; + private boolean getFromFile = false; /** * Wait 1ms on lock by default. @@ -243,8 +244,8 @@ Map> reportTablesWithMissingRegionsInMeta(String... nameSpa Map> report; try (final FsRegionsMetaRecoverer fsRegionsMetaRecoverer = new FsRegionsMetaRecoverer(this.conf)) { - report = fsRegionsMetaRecoverer.reportTablesMissingRegions( - formatNameSpaceTableParam(nameSpaceOrTable)); + report = fsRegionsMetaRecoverer.reportTablesMissingRegions(getFromArgsOrFiles( + formatNameSpaceTableParam(nameSpaceOrTable))); } catch (IOException e) { LOG.error("Error reporting missing regions: ", e); throw e; @@ -268,7 +269,7 @@ Map> extraRegionsInMeta(String[] args) Map> result = new HashMap<>(); try (final FsRegionsMetaRecoverer fsRegionsMetaRecoverer = new FsRegionsMetaRecoverer(this.conf)) { - List namespacesTables = formatNameSpaceTableParam(commandLine.getArgs()); + List namespacesTables = getFromArgsOrFiles(formatNameSpaceTableParam(commandLine.getArgs())); Map> reportMap = fsRegionsMetaRecoverer.reportTablesExtraRegions(namespacesTables); final List toFix = new ArrayList<>(); @@ -305,16 +306,12 @@ Map> extraRegionsInMeta(String[] args) return result; } - private List formatNameSpaceTableParam(String... nameSpaceOrTable) { - return nameSpaceOrTable != null ? Arrays.asList(nameSpaceOrTable) : null; - } - List>> addMissingRegionsInMetaForTables(String... nameSpaceOrTable) throws IOException { try (final FsRegionsMetaRecoverer fsRegionsMetaRecoverer = new FsRegionsMetaRecoverer(this.conf)) { - return fsRegionsMetaRecoverer.addMissingRegionsInMetaForTables( - formatNameSpaceTableParam(nameSpaceOrTable)); + return fsRegionsMetaRecoverer.addMissingRegionsInMetaForTables(getFromArgsOrFiles( + formatNameSpaceTableParam(nameSpaceOrTable))); } catch (IOException e) { LOG.error("Error adding missing regions: ", e); throw e; @@ -324,9 +321,7 @@ List>> addMissingRegionsInMetaForTables(String... List assigns(Hbck hbck, String[] args) throws IOException { Options options = new Options(); Option override = Option.builder("o").longOpt("override").build(); - Option inputFile = Option.builder("i").longOpt("inputFiles").build(); options.addOption(override); - options.addOption(inputFile); // Parse command-line. CommandLineParser parser = new DefaultParser(); CommandLine commandLine; @@ -337,21 +332,8 @@ List assigns(Hbck hbck, String[] args) throws IOException { return null; } boolean overrideFlag = commandLine.hasOption(override.getOpt()); - List argList = commandLine.getArgList(); - if (!commandLine.hasOption(inputFile.getOpt())) { - return hbck.assigns(argList, overrideFlag); - } - List assignmentList = new ArrayList<>(); - for (String filePath : argList) { - try (InputStream fileStream = new FileInputStream(filePath)){ - LineIterator it = IOUtils.lineIterator(fileStream, "UTF-8"); - while (it.hasNext()) { - assignmentList.add(it.nextLine().trim()); - } - } - } - return hbck.assigns(assignmentList, overrideFlag); + return hbck.assigns(this.getFromArgsOrFiles(argList), overrideFlag); } List unassigns(Hbck hbck, String [] args) throws IOException { @@ -368,7 +350,30 @@ List unassigns(Hbck hbck, String [] args) throws IOException { return null; } boolean overrideFlag = commandLine.hasOption(override.getOpt()); - return hbck.unassigns(commandLine.getArgList(), overrideFlag); + return hbck.unassigns(getFromArgsOrFiles(commandLine.getArgList()), overrideFlag); + } + + private List formatNameSpaceTableParam(String... nameSpaceOrTable) { + return nameSpaceOrTable != null ? Arrays.asList(nameSpaceOrTable) : null; + } + + /** + * @return Read arguments from a list of input files + */ + private List getFromArgsOrFiles(List args) throws IOException { + if (!getFromFile || args == null) { + return args; + } + List argList = new ArrayList<>(); + for (String filePath : args) { + try (InputStream fileStream = new FileInputStream(filePath)){ + LineIterator it = IOUtils.lineIterator(fileStream, "UTF-8"); + while (it.hasNext()) { + argList.add(it.nextLine().trim()); + } + } + } + return argList; } /** @@ -528,7 +533,6 @@ private static void usageAssigns(PrintWriter writer) { writer.println(" " + ASSIGNS + " [OPTIONS] ..."); writer.println(" Options:"); writer.println(" -o,--override override ownership by another procedure"); - writer.println(" -i,--inputFiles take one or more files of encoded region names"); writer.println(" A 'raw' assign that can be used even during Master initialization (if"); writer.println(" the -skip flag is specified). Skirts Coprocessors. Pass one or more"); writer.println(" encoded region names. 1588230740 is the hard-coded name for the"); @@ -538,7 +542,7 @@ private static void usageAssigns(PrintWriter writer) { writer.println(" Returns the pid(s) of the created AssignProcedure(s) or -1 if none."); writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); writer.println(" Each file contains encoded region names, one per line. For example:"); - writer.println(" $ HBCK2 assigns -i fileName1 fileName2"); + writer.println(" $ HBCK2 -i assigns fileName1 fileName2"); } private static void usageBypass(PrintWriter writer) { @@ -743,6 +747,9 @@ private static void usageUnassigns(PrintWriter writer) { writer.println(" of what a userspace encoded region name looks like. For example:"); writer.println(" $ HBCK2 unassigns 1588230740 de00010733901a05f5a2a3a382e27dd4"); writer.println(" Returns the pid(s) of the created UnassignProcedure(s) or -1 if none."); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains encoded region names, one per line. For example:"); + writer.println(" $ HBCK2 -i unassigns fileName1 fileName2"); writer.println(); writer.println(" SEE ALSO, org.apache.hbase.hbck1.OfflineMetaRepair, the offline"); writer.println(" hbase:meta tool. See the HBCK2 README for how to use."); @@ -818,6 +825,9 @@ public int run(String[] args) throws IOException { Option skip = Option.builder("s").longOpt("skip"). desc("skip hbase version check (PleaseHoldException)").build(); options.addOption(skip); + Option inputFile = Option.builder("i").longOpt("inputFiles") + .desc("take one or more files to read the args from").build(); + options.addOption(inputFile); // Parse command-line. CommandLineParser parser = new DefaultParser(); @@ -868,6 +878,9 @@ public int run(String[] args) throws IOException { if (commandLine.hasOption(skip.getOpt())) { skipCheck = true; } + if (commandLine.hasOption(inputFile.getOpt())) { + getFromFile = true; + } return doCommandLine(commandLine, options); } diff --git a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java index 840f9be38a..f3bd73d0a8 100644 --- a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java +++ b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java @@ -76,6 +76,7 @@ public class TestHBCK2 { valueOf(TestHBCK2.class.getSimpleName() + "-REGIONS_STATES"); private final static String ASSIGNS = "assigns"; private static final String EXTRA_REGIONS_IN_META = "extraRegionsInMeta"; + private final static String UNASSIGNS = "unassigns"; @Rule public TestName testName = new TestName(); @@ -124,6 +125,24 @@ public void testSetTableStateInMeta() throws IOException { } } + @Test + public void testUnAssigns() throws IOException { + try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { + List regions = admin.getRegions(TABLE_NAME); + for (RegionInfo ri : regions) { + RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). + getRegionStates().getRegionState(ri.getEncodedName()); + LOG.info("RS: {}", rs.toString()); + } + String[] regionStrsArray = + regions.stream().map(RegionInfo::getEncodedName).toArray(String[]::new); + File testFile = new File(TEST_UTIL.getDataTestDir().toString(), "inputForUnAssignsTest"); + writeStringsToAFile(testFile, regionStrsArray); + String result = testRunWithArgs(new String[]{"-i", UNASSIGNS, testFile.toString()}); + validateRegionEndState(getPidsFromResult(result), regions, false); + } + } + @Test public void testAssigns() throws IOException { try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { @@ -139,8 +158,7 @@ public void testAssigns() throws IOException { try (ClusterConnection connection = this.hbck2.connect(); Hbck hbck = connection.getHbck()) { unassigns(regions, regionStrsArray); List pids = this.hbck2.assigns(hbck, regionStrsArray); - waitOnPids(pids); - validateOpen(regions); + validateRegionEndState(pids,regions, true); // What happens if crappy region list passed? pids = this.hbck2.assigns(hbck, Arrays.stream(new String[]{"a", "some rubbish name"}). collect(Collectors.toList()).toArray(new String[]{})); @@ -151,20 +169,9 @@ public void testAssigns() throws IOException { // test input files unassigns(regions, regionStrsArray); File testFile = new File(TEST_UTIL.getDataTestDir().toString(), "inputForAssignsTest"); - try (FileOutputStream output = new FileOutputStream(testFile, false)) { - for (String regionStr : regionStrsArray) { - output.write((regionStr + System.lineSeparator()).getBytes()); - } - } - String result = testRunWithArgs(new String[]{ASSIGNS, "-i", testFile.toString()}); - Scanner scanner = new Scanner(result).useDelimiter("[\\D]+"); - pids = new ArrayList<>(); - while (scanner.hasNext()) { - pids.add(scanner.nextLong()); - } - scanner.close(); - waitOnPids(pids); - validateOpen(regions); + writeStringsToAFile(testFile, regionStrsArray); + String result = testRunWithArgs(new String[]{"-i", ASSIGNS, testFile.toString()}); + validateRegionEndState(getPidsFromResult(result), regions, true); } } } @@ -302,6 +309,23 @@ public void testFormatReportMissingInMetaOneMissing() throws IOException { assertTrue(result.contains(expectedResult)); } + private void writeStringsToAFile(File testFile, String[] strs) throws IOException { + try (FileOutputStream output = new FileOutputStream(testFile, false)) { + for (String regionStr : strs) { + output.write((regionStr + System.lineSeparator()).getBytes()); + } + } + } + private List getPidsFromResult(String result) { + Scanner scanner = new Scanner(result).useDelimiter("[\\D]+"); + List pids = new ArrayList<>(); + while (scanner.hasNext()) { + pids.add(scanner.nextLong()); + } + scanner.close(); + return pids; + } + private void unassigns(List regions, String[] regionStrsArray) throws IOException { try (ClusterConnection connection = this.hbck2.connect(); Hbck hbck = connection.getHbck()) { List pids = this.hbck2.unassigns(hbck, regionStrsArray); @@ -315,13 +339,13 @@ private void unassigns(List regions, String[] regionStrsArray) throw } } - - private void validateOpen(List regions) { + private void validateRegionEndState(List pids, List regions, boolean open) { + waitOnPids(pids); for (RegionInfo ri : regions) { RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). getRegionStates().getRegionState(ri.getEncodedName()); LOG.info("RS: {}", rs.toString()); - assertTrue(rs.toString(), rs.isOpened()); + assertTrue(rs.toString(), open? rs.isOpened() : rs.isClosed()); } } From d75bbaf06ea402e30282c6797b1759a0d563f400 Mon Sep 17 00:00:00 2001 From: Clara Xiong Date: Sun, 21 Jun 2020 14:23:48 -0700 Subject: [PATCH 2/6] updates for review feedback --- hbase-hbck2/README.md | 1 + .../src/main/java/org/apache/hbase/HBCK2.java | 58 +++++++++++++------ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/hbase-hbck2/README.md b/hbase-hbck2/README.md index 04961c8584..8804bb8341 100644 --- a/hbase-hbck2/README.md +++ b/hbase-hbck2/README.md @@ -91,6 +91,7 @@ The above command with no options or arguments passed will dump out the _HBCK2_ usage: HBCK2 [OPTIONS] COMMAND Options: -d,--debug run with debug output + -i, --inputfiles take one or more files to read the args from -h,--help output this help message -p,--hbase.zookeeper.property.clientPort port of hbase ensemble -q,--hbase.zookeeper.quorum hbase ensemble diff --git a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java index 2021af526b..25e07f48f3 100644 --- a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java +++ b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java @@ -37,6 +37,7 @@ import java.util.concurrent.Future; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; @@ -402,14 +403,14 @@ private List bypass(String[] args) throws IOException { if (commandLine.hasOption(wait.getOpt())) { lockWait = Integer.parseInt(commandLine.getOptionValue(wait.getOpt())); } - String[] pidStrs = commandLine.getArgs(); - if (pidStrs == null || pidStrs.length <= 0) { + List pidStrs = getFromArgsOrFiles(commandLine.getArgList()); + if (pidStrs == null || pidStrs.size() <= 0) { showErrorMessage("No pids supplied."); return null; } boolean overrideFlag = commandLine.hasOption(override.getOpt()); boolean recursiveFlag = commandLine.hasOption(recursive.getOpt()); - List pids = Arrays.stream(pidStrs).map(Long::valueOf).collect(Collectors.toList()); + List pids = pidStrs.stream().map(Long::valueOf).collect(Collectors.toList()); try (ClusterConnection connection = connect(); Hbck hbck = connection.getHbck()) { checkFunctionSupported(connection, BYPASS); return hbck.bypassProcedure(pids, lockWait, overrideFlag, recursiveFlag); @@ -417,8 +418,9 @@ private List bypass(String[] args) throws IOException { } List scheduleRecoveries(Hbck hbck, String[] args) throws IOException { + List arglist = getFromArgsOrFiles(Arrays.asList(args)); List serverNames = new ArrayList<>(); - for (String serverName: args) { + for (String serverName: arglist) { serverNames.add(parseServerName(serverName)); } return hbck.scheduleServerCrashProcedure(serverNames); @@ -503,7 +505,7 @@ private static String getCommandUsage() { private static void usageAddFsRegionsMissingInMeta(PrintWriter writer) { writer.println(" " + ADD_MISSING_REGIONS_IN_META_FOR_TABLES + " ..."); + + "NAMESPACE:TABLENAME|INPUTFILE_FOR_>..."); writer.println(" Options:"); writer.println(" -d,--force_disable aborts fix for table if disable fails."); writer.println(" To be used when regions missing from hbase:meta but directories"); @@ -527,10 +529,13 @@ private static void usageAddFsRegionsMissingInMeta(PrintWriter writer) { writer.println(" Returns HBCK2 an 'assigns' command with all re-inserted regions."); writer.println(" SEE ALSO: " + REPORT_MISSING_REGIONS_IN_META); writer.println(" SEE ALSO: " + FIX_META); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains , one per line. For example:"); + writer.println(" $ HBCK2 -i" + ADD_MISSING_REGIONS_IN_META_FOR_TABLES + "fileName1 fileName2"); } private static void usageAssigns(PrintWriter writer) { - writer.println(" " + ASSIGNS + " [OPTIONS] ..."); + writer.println(" " + ASSIGNS + " [OPTIONS] ..."); writer.println(" Options:"); writer.println(" -o,--override override ownership by another procedure"); writer.println(" A 'raw' assign that can be used even during Master initialization (if"); @@ -538,15 +543,15 @@ private static void usageAssigns(PrintWriter writer) { writer.println(" encoded region names. 1588230740 is the hard-coded name for the"); writer.println(" hbase:meta region and de00010733901a05f5a2a3a382e27dd4 is an example of"); writer.println(" what a user-space encoded region name looks like. For example:"); - writer.println(" $ HBCK2 assigns 1588230740 de00010733901a05f5a2a3a382e27dd4"); + writer.println(" $ HBCK2 " + ASSIGNS + " 1588230740 de00010733901a05f5a2a3a382e27dd4"); writer.println(" Returns the pid(s) of the created AssignProcedure(s) or -1 if none."); writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); writer.println(" Each file contains encoded region names, one per line. For example:"); - writer.println(" $ HBCK2 -i assigns fileName1 fileName2"); + writer.println(" $ HBCK2 -i " + ASSIGNS + " fileName1 fileName2"); } private static void usageBypass(PrintWriter writer) { - writer.println(" " + BYPASS + " [OPTIONS] ..."); + writer.println(" " + BYPASS + " [OPTIONS] |..."); writer.println(" Options:"); writer.println(" -o,--override override if procedure is running/stuck"); writer.println(" -r,--recursive bypass parent and its children. SLOW! EXPENSIVE!"); @@ -558,10 +563,13 @@ private static void usageBypass(PrintWriter writer) { writer.println(" procedure has children. Add 'recursive' if all you have is a parent pid"); writer.println(" to finish parent and children. This is SLOW, and dangerous so use"); writer.println(" selectively. Does not always work."); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains pids, one per line. For example:"); + writer.println(" $ HBCK2 -i" + BYPASS + "fileName1 fileName2"); } private static void usageFilesystem(PrintWriter writer) { - writer.println(" " + FILESYSTEM + " [OPTIONS] [...]"); + writer.println(" " + FILESYSTEM + " [OPTIONS] [...]"); writer.println(" Options:"); writer.println(" -f, --fix sideline corrupt hfiles, bad links, and references."); writer.println(" Report on corrupt hfiles, references, broken links, and integrity."); @@ -570,6 +578,9 @@ private static void usageFilesystem(PrintWriter writer) { writer.println(" more tablenames to narrow checkup. Default checks all tables and"); writer.println(" restores 'hbase.version' if missing. Interacts with the filesystem"); writer.println(" only! Modified regions need to be reopened to pick-up changes."); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains table names, one per line. For example:"); + writer.println(" $ HBCK2 -i" + FILESYSTEM + "fileName1 fileName2"); } private static void usageFixMeta(PrintWriter writer) { @@ -624,7 +635,7 @@ private static void usageReplication(PrintWriter writer) { private static void usageExtraRegionsInMeta(PrintWriter writer) { writer.println(" " + EXTRA_REGIONS_IN_META + " ..."); + + "NAMESPACE:TABLENAME|INPUTFILE_FOR_>..."); writer.println(" Options:"); writer.println(" -f, --fix fix meta by removing all extra regions found."); writer.println(" Reports regions present on hbase:meta, but with no related "); @@ -647,11 +658,14 @@ private static void usageExtraRegionsInMeta(PrintWriter writer) { writer.println(" $ HBCK2 " + EXTRA_REGIONS_IN_META + " default:table_1 ns1"); writer.println(" Returns list of extra regions for each table passed as parameter, or"); writer.println(" for each table on namespaces specified as parameter."); - } + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains , one per line. For example:"); + writer.println(" $ HBCK2 -i" + EXTRA_REGIONS_IN_META + "fileName1 fileName2"); +} private static void usageReportMissingRegionsInMeta(PrintWriter writer) { writer.println(" " + REPORT_MISSING_REGIONS_IN_META + " ..."); + + "NAMESPACE:TABLENAME|INPUTFILE_FOR_>..."); writer.println(" To be used when regions missing from hbase:meta but directories"); writer.println(" are present still in HDFS. Can happen if user has run _hbck1_"); writer.println(" 'OfflineMetaRepair' against an hbase-2.x cluster. This is a CHECK only"); @@ -671,12 +685,15 @@ private static void usageReportMissingRegionsInMeta(PrintWriter writer) { writer.println(" namespace, otherwise it will assume as a namespace value."); writer.println(" An example triggering missing regions execute for tables 'table_1'"); writer.println(" and 'table_2', under default namespace:"); - writer.println(" $ HBCK2 reportMissingRegionsInMeta default:table_1 default:table_2"); + writer.println(" $ HBCK2 " + REPORT_MISSING_REGIONS_IN_META + " default:table_1 default:table_2"); writer.println(" An example triggering missing regions execute for table 'table_1'"); writer.println(" under default namespace, and for all tables from namespace 'ns1':"); - writer.println(" $ HBCK2 reportMissingRegionsInMeta default:table_1 ns1"); + writer.println(" $ HBCK2 " + REPORT_MISSING_REGIONS_IN_META + " default:table_1 ns1"); writer.println(" Returns list of missing regions for each table passed as parameter, or"); writer.println(" for each table on namespaces specified as parameter."); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains , one per line. For example:"); + writer.println(" $ HBCK2 -i " + REPORT_MISSING_REGIONS_IN_META + " fileName1 fileName2"); } private static void usageSetRegionState(PrintWriter writer) { @@ -698,7 +715,7 @@ private static void usageSetRegionState(PrintWriter writer) { writer.println(" such as 'assign' or 'split'. You can get a view of running procedures"); writer.println(" in the hbase shell using the 'list_procedures' command. An example"); writer.println(" setting region 'de00010733901a05f5a2a3a382e27dd4' to CLOSING:"); - writer.println(" $ HBCK2 setRegionState de00010733901a05f5a2a3a382e27dd4 CLOSING"); + writer.println(" $ HBCK2 " + SET_REGION_STATE + " de00010733901a05f5a2a3a382e27dd4 CLOSING"); writer.println(" Returns \"0\" if region state changed and \"1\" otherwise."); } @@ -716,7 +733,7 @@ private static void usageSetTableState(PrintWriter writer) { } private static void usageScheduleRecoveries(PrintWriter writer) { - writer.println(" " + SCHEDULE_RECOVERIES + " ..."); + writer.println(" " + SCHEDULE_RECOVERIES + " ..."); writer.println(" Schedule ServerCrashProcedure(SCP) for list of RegionServers. Format"); writer.println(" server name as ',,' (See HBase UI/logs)."); writer.println(" Example using RegionServer 'a.example.org,29100,1540348649479':"); @@ -724,6 +741,9 @@ private static void usageScheduleRecoveries(PrintWriter writer) { writer.println(" Returns the pid(s) of the created ServerCrashProcedure(s) or -1 if"); writer.println(" no procedure created (see master logs for why not)."); writer.println(" Command support added in hbase versions 2.0.3, 2.1.2, 2.2.0 or newer."); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains server names, one per line. For example:"); + writer.println(" $ HBCK2 -i " + SCHEDULE_RECOVERIES + " fileName1 fileName2"); } private static void usageRecoverUnknown(PrintWriter writer) { @@ -737,7 +757,7 @@ private static void usageRecoverUnknown(PrintWriter writer) { } private static void usageUnassigns(PrintWriter writer) { - writer.println(" " + UNASSIGNS + " ..."); + writer.println(" " + UNASSIGNS + " ..."); writer.println(" Options:"); writer.println(" -o,--override override ownership by another procedure"); writer.println(" A 'raw' unassign that can be used even during Master initialization"); @@ -749,7 +769,7 @@ private static void usageUnassigns(PrintWriter writer) { writer.println(" Returns the pid(s) of the created UnassignProcedure(s) or -1 if none."); writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); writer.println(" Each file contains encoded region names, one per line. For example:"); - writer.println(" $ HBCK2 -i unassigns fileName1 fileName2"); + writer.println(" $ HBCK2 -i " + UNASSIGNS + " fileName1 fileName2"); writer.println(); writer.println(" SEE ALSO, org.apache.hbase.hbck1.OfflineMetaRepair, the offline"); writer.println(" hbase:meta tool. See the HBCK2 README for how to use."); From d74cc53b9c2eb9569d7e64158809e7ac892e82a3 Mon Sep 17 00:00:00 2001 From: Clara Xiong Date: Mon, 28 Feb 2022 16:56:25 -0800 Subject: [PATCH 3/6] update README --- hbase-hbck2/README.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/hbase-hbck2/README.md b/hbase-hbck2/README.md index 8804bb8341..4038b6e7c9 100644 --- a/hbase-hbck2/README.md +++ b/hbase-hbck2/README.md @@ -104,6 +104,7 @@ Command: addFsRegionsMissingInMeta ... Options: -d,--force_disable aborts fix for table if disable fails. + -i,--inputFiles take one or more encoded region names To be used when regions missing from hbase:meta but directories are present still in HDFS. Can happen if user has run _hbck1_ 'OfflineMetaRepair' against an hbase-2.x cluster. Needs hbase:meta @@ -124,6 +125,10 @@ Command: Returns HBCK2 an 'assigns' command with all re-inserted regions. SEE ALSO: reportMissingRegionsInMeta SEE ALSO: fixMeta + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one per line. For example: + For example: + $ HBCK2 -i addFsRegionsMissingInMeta fileName1 fileName2 assigns [OPTIONS] ... Options: @@ -151,11 +156,14 @@ Command: need Master restart to clear locks still held. Bypass fails if procedure has children. Add 'recursive' if all you have is a parent pid to finish parent and children. This is SLOW, and dangerous so use - selectively. Does not always work. + selectively. Does not always work.If -i or --inputFiles is specified, pass one or more input file names. + Each file contains PID's, one per line. For example: + $ HBCK2 -i bypass fileName1 fileName2 extraRegionsInMeta ... Options: -f, --fix fix meta by removing all extra regions found. + -i, --inputFile take one or more files to read the args from Reports regions present on hbase:meta, but with no related directories on the file system. Needs hbase:meta to be online. For each table name passed as parameter, performs diff @@ -175,17 +183,23 @@ Command: $ HBCK2 extraRegionsInMeta default:table_1 ns1 Returns list of extra regions for each table passed as parameter, or for each table on namespaces specified as parameter. + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one per line. For example: + $ HBCK2 -i extraRegionsInMeta fileName1 fileName2 filesystem [OPTIONS] [...] Options: -f, --fix sideline corrupt hfiles, bad links, and references. + -i, --inputFile take one or more files to read the args from Report on corrupt hfiles, references, broken links, and integrity. Pass '--fix' to sideline corrupt files and links. '--fix' does NOT fix integrity issues; i.e. 'holes' or 'orphan' regions. Pass one or more tablenames to narrow checkup. Default checks all tables and restores 'hbase.version' if missing. Interacts with the filesystem - only! Modified regions need to be reopened to pick-up changes. - + only! Modified regions need to be reopened to pick-up changes. + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one per line. For example: + $ HBCK2 -i extraRegionsInMeta fileName1 fileName2 fixMeta Do a server-side fix of bad or inconsistent state in hbase:meta. Available in hbase 2.2.1/2.1.6 or newer versions. Master UI has @@ -225,11 +239,15 @@ Command: replication [OPTIONS] [...] Options: -f, --fix fix any replication issues found. + -i, --inputFile take one or more files to read the args from Looks for undeleted replication queues and deletes them if passed the '--fix' option. Pass a table name to check for replication barrier and - purge if '--fix'. + purge if '--fix'. If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one per line. For example: + $ HBCK2 -i replication fileName1 fileName2 reportMissingRegionsInMeta ... + -i, --inputFile take one or more files to read the args from To be used when regions missing from hbase:meta but directories are present still in HDFS. Can happen if user has run _hbck1_ 'OfflineMetaRepair' against an hbase-2.x cluster. This is a CHECK only @@ -254,6 +272,9 @@ Command: $ HBCK2 reportMissingRegionsInMeta default:table_1 ns1 Returns list of missing regions for each table passed as parameter, or for each table on namespaces specified as parameter. + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one per line. For example: + $ HBCK2 -i reportMissingRegionsInMeta fileName1 fileName2 setRegionState Possible region states: @@ -284,6 +305,7 @@ Command: Returns whatever the previous table state was. scheduleRecoveries ... + -i, --inputFile take one or more files to read the args from Schedule ServerCrashProcedure(SCP) for list of RegionServers. Format server name as ',,' (See HBase UI/logs). Example using RegionServer 'a.example.org,29100,1540348649479': @@ -291,10 +313,14 @@ Command: Returns the pid(s) of the created ServerCrashProcedure(s) or -1 if no procedure created (see master logs for why not). Command support added in hbase versions 2.0.3, 2.1.2, 2.2.0 or newer. + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one per line. For example: + $ HBCK2 -i scheduleRecoveries fileName1 fileName2 unassigns ... Options: -o,--override override ownership by another procedure + -i, --inputFile take one or more files to read the args from A 'raw' unassign that can be used even during Master initialization (if the -skip flag is specified). Skirts Coprocessors. Pass one or more encoded region names. 1588230740 is the hard-coded name for the From 4735bf727d5f9c30e29a84dae70cac7c2fba6662 Mon Sep 17 00:00:00 2001 From: Clara Xiong Date: Mon, 28 Feb 2022 19:54:01 -0800 Subject: [PATCH 4/6] checkstyle fix add unit test for the new -i option update README --- hbase-hbck2/README.md | 18 ++++------ .../src/main/java/org/apache/hbase/HBCK2.java | 34 +++++++++++-------- .../hbase/TestHBCKCommandLineParsing.java | 9 +++++ 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/hbase-hbck2/README.md b/hbase-hbck2/README.md index 4038b6e7c9..0226f6108d 100644 --- a/hbase-hbck2/README.md +++ b/hbase-hbck2/README.md @@ -93,6 +93,7 @@ Options: -d,--debug run with debug output -i, --inputfiles take one or more files to read the args from -h,--help output this help message + -i,--inputFiles take one or more encoded region names -p,--hbase.zookeeper.property.clientPort port of hbase ensemble -q,--hbase.zookeeper.quorum hbase ensemble -s,--skip skip hbase version check @@ -104,7 +105,6 @@ Command: addFsRegionsMissingInMeta ... Options: -d,--force_disable aborts fix for table if disable fails. - -i,--inputFiles take one or more encoded region names To be used when regions missing from hbase:meta but directories are present still in HDFS. Can happen if user has run _hbck1_ 'OfflineMetaRepair' against an hbase-2.x cluster. Needs hbase:meta @@ -133,7 +133,6 @@ Command: assigns [OPTIONS] ... Options: -o,--override override ownership by another procedure - -i,--inputFiles take one or more encoded region names A 'raw' assign that can be used even during Master initialization (if the -skip flag is specified). Skirts Coprocessors. Pass one or more encoded region names. 1588230740 is the hard-coded name for the @@ -149,21 +148,20 @@ Command: -o,--override override if procedure is running/stuck -r,--recursive bypass parent and its children. SLOW! EXPENSIVE! -w,--lockWait milliseconds to wait before giving up; default=1 - -i, --inputFile take one or more files to read the args from - Pass one (or more) procedure 'pid's to skip to procedure finish. Parent + Pass one (or more) procedure 'pid's to skip to procedure finish. Parent of bypassed procedure will also be skipped to the finish. Entities will be left in an inconsistent state and will require manual fixup. May need Master restart to clear locks still held. Bypass fails if procedure has children. Add 'recursive' if all you have is a parent pid to finish parent and children. This is SLOW, and dangerous so use - selectively. Does not always work.If -i or --inputFiles is specified, pass one or more input file names. + selectively. Does not always work. + If -i or --inputFiles is specified, pass one or more input file names. Each file contains PID's, one per line. For example: $ HBCK2 -i bypass fileName1 fileName2 extraRegionsInMeta ... Options: -f, --fix fix meta by removing all extra regions found. - -i, --inputFile take one or more files to read the args from Reports regions present on hbase:meta, but with no related directories on the file system. Needs hbase:meta to be online. For each table name passed as parameter, performs diff @@ -190,13 +188,12 @@ Command: filesystem [OPTIONS] [...] Options: -f, --fix sideline corrupt hfiles, bad links, and references. - -i, --inputFile take one or more files to read the args from Report on corrupt hfiles, references, broken links, and integrity. Pass '--fix' to sideline corrupt files and links. '--fix' does NOT fix integrity issues; i.e. 'holes' or 'orphan' regions. Pass one or more tablenames to narrow checkup. Default checks all tables and restores 'hbase.version' if missing. Interacts with the filesystem - only! Modified regions need to be reopened to pick-up changes. + only! Modified regions need to be reopened to pick-up changes. If -i or --inputFiles is specified, pass one or more input file names. Each file contains , one per line. For example: $ HBCK2 -i extraRegionsInMeta fileName1 fileName2 @@ -239,7 +236,6 @@ Command: replication [OPTIONS] [...] Options: -f, --fix fix any replication issues found. - -i, --inputFile take one or more files to read the args from Looks for undeleted replication queues and deletes them if passed the '--fix' option. Pass a table name to check for replication barrier and purge if '--fix'. If -i or --inputFiles is specified, pass one or more input file names. @@ -247,8 +243,7 @@ Command: $ HBCK2 -i replication fileName1 fileName2 reportMissingRegionsInMeta ... - -i, --inputFile take one or more files to read the args from - To be used when regions missing from hbase:meta but directories + To be used when regions missing from hbase:meta but directories are present still in HDFS. Can happen if user has run _hbck1_ 'OfflineMetaRepair' against an hbase-2.x cluster. This is a CHECK only method, designed for reporting purposes and doesn't perform any @@ -320,7 +315,6 @@ Command: unassigns ... Options: -o,--override override ownership by another procedure - -i, --inputFile take one or more files to read the args from A 'raw' unassign that can be used even during Master initialization (if the -skip flag is specified). Skirts Coprocessors. Pass one or more encoded region names. 1588230740 is the hard-coded name for the diff --git a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java index 25e07f48f3..5259bcab60 100644 --- a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java +++ b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java @@ -37,7 +37,6 @@ import java.util.concurrent.Future; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; @@ -270,7 +269,8 @@ Map> extraRegionsInMeta(String[] args) Map> result = new HashMap<>(); try (final FsRegionsMetaRecoverer fsRegionsMetaRecoverer = new FsRegionsMetaRecoverer(this.conf)) { - List namespacesTables = getFromArgsOrFiles(formatNameSpaceTableParam(commandLine.getArgs())); + List namespacesTables = + getFromArgsOrFiles(formatNameSpaceTableParam(commandLine.getArgs())); Map> reportMap = fsRegionsMetaRecoverer.reportTablesExtraRegions(namespacesTables); final List toFix = new ArrayList<>(); @@ -530,8 +530,10 @@ private static void usageAddFsRegionsMissingInMeta(PrintWriter writer) { writer.println(" SEE ALSO: " + REPORT_MISSING_REGIONS_IN_META); writer.println(" SEE ALSO: " + FIX_META); writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); - writer.println(" Each file contains , one per line. For example:"); - writer.println(" $ HBCK2 -i" + ADD_MISSING_REGIONS_IN_META_FOR_TABLES + "fileName1 fileName2"); + writer.println(" Each file contains , one per line."); + writer.println(" For example:"); + writer.println(" $ HBCK2 -i" + ADD_MISSING_REGIONS_IN_META_FOR_TABLES + + "fileName1 fileName2"); } private static void usageAssigns(PrintWriter writer) { @@ -635,7 +637,7 @@ private static void usageReplication(PrintWriter writer) { private static void usageExtraRegionsInMeta(PrintWriter writer) { writer.println(" " + EXTRA_REGIONS_IN_META + " >..."); + + "NAMESPACE:TABLENAME|INPUTFILE_FOR_>..."); writer.println(" Options:"); writer.println(" -f, --fix fix meta by removing all extra regions found."); writer.println(" Reports regions present on hbase:meta, but with no related "); @@ -652,16 +654,17 @@ private static void usageExtraRegionsInMeta(PrintWriter writer) { writer.println(" An example triggering extra regions report for tables 'table_1'"); writer.println(" and 'table_2', under default namespace:"); writer.println(" $ HBCK2 " + EXTRA_REGIONS_IN_META + - " default:table_1 default:table_2"); + " default:table_1 default:table_2"); writer.println(" An example triggering missing regions report for table 'table_1'"); writer.println(" under default namespace, and for all tables from namespace 'ns1':"); writer.println(" $ HBCK2 " + EXTRA_REGIONS_IN_META + " default:table_1 ns1"); writer.println(" Returns list of extra regions for each table passed as parameter, or"); writer.println(" for each table on namespaces specified as parameter."); writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); - writer.println(" Each file contains , one per line. For example:"); + writer.println(" Each file contains , one per line."); + writer.println(" For example:"); writer.println(" $ HBCK2 -i" + EXTRA_REGIONS_IN_META + "fileName1 fileName2"); -} + } private static void usageReportMissingRegionsInMeta(PrintWriter writer) { writer.println(" " + REPORT_MISSING_REGIONS_IN_META + " , one per line. For example:"); + writer.println(" Each file contains , one per line.);" + + "For example:"); writer.println(" $ HBCK2 -i " + REPORT_MISSING_REGIONS_IN_META + " fileName1 fileName2"); } @@ -715,7 +720,8 @@ private static void usageSetRegionState(PrintWriter writer) { writer.println(" such as 'assign' or 'split'. You can get a view of running procedures"); writer.println(" in the hbase shell using the 'list_procedures' command. An example"); writer.println(" setting region 'de00010733901a05f5a2a3a382e27dd4' to CLOSING:"); - writer.println(" $ HBCK2 " + SET_REGION_STATE + " de00010733901a05f5a2a3a382e27dd4 CLOSING"); + writer.println(" $ HBCK2 " + SET_REGION_STATE + + " de00010733901a05f5a2a3a382e27dd4 CLOSING"); writer.println(" Returns \"0\" if region state changed and \"1\" otherwise."); } @@ -845,9 +851,9 @@ public int run(String[] args) throws IOException { Option skip = Option.builder("s").longOpt("skip"). desc("skip hbase version check (PleaseHoldException)").build(); options.addOption(skip); - Option inputFile = Option.builder("i").longOpt("inputFiles") + Option inputFiles = Option.builder("i").longOpt("inputFiles") .desc("take one or more files to read the args from").build(); - options.addOption(inputFile); + options.addOption(inputFiles); // Parse command-line. CommandLineParser parser = new DefaultParser(); @@ -898,7 +904,7 @@ public int run(String[] args) throws IOException { if (commandLine.hasOption(skip.getOpt())) { skipCheck = true; } - if (commandLine.hasOption(inputFile.getOpt())) { + if (commandLine.hasOption(inputFiles.getOpt())) { getFromFile = true; } return doCommandLine(commandLine, options); diff --git a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java index da37648a84..050a65faeb 100644 --- a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java +++ b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; @@ -66,6 +67,14 @@ public void testCommandWithOptions() throws IOException { hbck.run(new String[]{"bypass", "--lockWait=3", "--override", "--recursive", "x"}); } + @Test (expected=FileNotFoundException.class) + public void testInputFileOption() throws IOException { + HBCK2 hbck = new HBCK2(TEST_UTIL.getConfiguration()); + // The 'x' below should cause the io exception for file not found. + // The Options should all be good. + hbck.run(new String[]{"--inputFile", "bypass", "--override", "x"}); + } + @Test (expected=IllegalArgumentException.class) public void testSetRegionStateCommandInvalidState() throws IOException { HBCK2 hbck = new HBCK2(TEST_UTIL.getConfiguration()); From 2090da038d942c91f8c967297bc5bdffdc67de0a Mon Sep 17 00:00:00 2001 From: Clara Xiong Date: Tue, 1 Mar 2022 16:30:50 -0800 Subject: [PATCH 5/6] accept input files for setRegionState and setTableState unit test fix --- hbase-hbck2/README.md | 8 + .../src/main/java/org/apache/hbase/HBCK2.java | 144 +++++++++++++----- .../test/java/org/apache/hbase/TestHBCK2.java | 64 ++++++++ .../hbase/TestHBCKCommandLineParsing.java | 3 +- 4 files changed, 182 insertions(+), 37 deletions(-) diff --git a/hbase-hbck2/README.md b/hbase-hbck2/README.md index 0226f6108d..1d9fd5c626 100644 --- a/hbase-hbck2/README.md +++ b/hbase-hbck2/README.md @@ -288,6 +288,10 @@ Command: setting region 'de00010733901a05f5a2a3a382e27dd4' to CLOSING: $ HBCK2 setRegionState de00010733901a05f5a2a3a382e27dd4 CLOSING Returns "0" if region state changed and "1" otherwise. + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one pair per line. + For example: + $ HBCK2 -i setRegionState fileName1 fileName2 setTableState Possible table states: ENABLED, DISABLED, DISABLING, ENABLING @@ -298,6 +302,10 @@ Command: An example making table name 'user' ENABLED: $ HBCK2 setTableState users ENABLED Returns whatever the previous table state was. + If -i or --inputFiles is specified, pass one or more input file names. + Each file contains , one pair per line. + For example: + $ HBCK2 -i setTableState fileName1 fileName2 scheduleRecoveries ... -i, --inputFile take one or more files to read the args from diff --git a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java index 5259bcab60..1d0ed20210 100644 --- a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java +++ b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java @@ -191,6 +191,18 @@ TableState setTableState(Hbck hbck, TableName tableName, TableState.State state) return hbck.setTableStateInMeta(new TableState(tableName, state)); } + TableState setTableState(Hbck hbck, String[] args) + throws IOException { + if (args == null || args.length < 2) { + showErrorMessage(SET_TABLE_STATE + + " takes tablename and state arguments: e.g. user ENABLED, you entered: " + + Arrays.toString(args)); + return null; + } + return setTableState(hbck, TableName.valueOf(args[0]), + TableState.State.valueOf(args[1])); + } + int setRegionState(ClusterConnection connection, String region, RegionState.State newState) throws IOException { @@ -239,6 +251,15 @@ int setRegionState(ClusterConnection connection, String region, int replicaId, return EXIT_FAILURE; } + int setRegionState(ClusterConnection connection, String[] args) throws IOException { + if (args == null || args.length < 3) { + return EXIT_FAILURE; + } + RegionState.State state = RegionState.State.valueOf(args[2]); + int replicaId = Integer.valueOf(args[1]); + return setRegionState(connection, args[0], replicaId, state); + } + Map> reportTablesWithMissingRegionsInMeta(String... nameSpaceOrTable) throws IOException { Map> report; @@ -359,12 +380,19 @@ private List formatNameSpaceTableParam(String... nameSpaceOrTable) { } /** - * @return Read arguments from a list of input files + * @return Read arguments from args or a list of input files */ private List getFromArgsOrFiles(List args) throws IOException { if (!getFromFile || args == null) { return args; } + return getFromFiles(args); + } + + /** + * @return Read arguments from a list of input files + */ + private List getFromFiles(List args) throws IOException { List argList = new ArrayList<>(); for (String filePath : args) { try (InputStream fileStream = new FileInputStream(filePath)){ @@ -704,9 +732,7 @@ private static void usageReportMissingRegionsInMeta(PrintWriter writer) { private static void usageSetRegionState(PrintWriter writer) { writer.println(" " + SET_REGION_STATE + " "); writer.println(" To set the replica region's state, it needs the primary region's "); - writer.println(" encoded regionname and replica id. The command will be "); - writer.println(" " + SET_REGION_STATE + " , "); - writer.println(" Possible region states:"); + writer.println(" encoded regionname and replica id. The states will be "); writer.println(" OFFLINE, OPENING, OPEN, CLOSING, CLOSED, SPLITTING, SPLIT,"); writer.println(" FAILED_OPEN, FAILED_CLOSE, MERGING, MERGED, SPLITTING_NEW,"); writer.println(" MERGING_NEW, ABNORMALLY_CLOSED"); @@ -723,6 +749,10 @@ private static void usageSetRegionState(PrintWriter writer) { writer.println(" $ HBCK2 " + SET_REGION_STATE + " de00010733901a05f5a2a3a382e27dd4 CLOSING"); writer.println(" Returns \"0\" if region state changed and \"1\" otherwise."); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains , one pair per line.);" + + "For example:"); + writer.println(" $ HBCK2 -i " + SET_REGION_STATE + " fileName1 fileName2"); } private static void usageSetTableState(PrintWriter writer) { @@ -736,6 +766,10 @@ private static void usageSetTableState(PrintWriter writer) { writer.println(" An example making table name 'user' ENABLED:"); writer.println(" $ HBCK2 setTableState users ENABLED"); writer.println(" Returns whatever the previous table state was."); + writer.println(" If -i or --inputFiles is specified, pass one or more input file names."); + writer.println(" Each file contains , one pair per line.);" + + "For example:"); + writer.println(" $ HBCK2 -i " + SET_TABLE_STATE + " fileName1 fileName2"); } private static void usageScheduleRecoveries(PrintWriter writer) { @@ -931,17 +965,32 @@ private int doCommandLine(CommandLine commandLine, Options options) throws IOExc // Case handlers all have same format. Check first that the server supports // the feature FIRST, then move to process the command. case SET_TABLE_STATE: - if (commands.length < 3) { - showErrorMessage(command + " takes tablename and state arguments: e.g. user ENABLED"); - return EXIT_FAILURE; + if (getFromFile){ + if (commands.length < 2) { + showErrorMessage(command + " takes a list of file names"); + return EXIT_FAILURE; + } + List argList = getFromFiles(Arrays.asList(purgeFirst(commands))); + try (ClusterConnection connection = connect(); Hbck hbck = connection.getHbck()) { + checkFunctionSupported(connection, command); + for (String line : argList) { + String[] args = line.split("\\s+"); + System.out.println(setTableState(hbck, args)); + } + } } - try (ClusterConnection connection = connect(); Hbck hbck = connection.getHbck()) { - checkFunctionSupported(connection, command); - System.out.println(setTableState(hbck, TableName.valueOf(commands[1]), - TableState.State.valueOf(commands[2]))); + else { + if (commands.length < 3) { + showErrorMessage(SET_TABLE_STATE + + " takes tablename and state arguments: e.g. user ENABLED"); + return EXIT_FAILURE; + } + try (ClusterConnection connection = connect(); Hbck hbck = connection.getHbck()) { + checkFunctionSupported(connection, command); + System.out.println(setTableState(hbck, purgeFirst(commands))); + } } break; - case ASSIGNS: if (commands.length < 2) { showErrorMessage(command + " takes one or more encoded region names"); @@ -983,31 +1032,29 @@ private int doCommandLine(CommandLine commandLine, Options options) throws IOExc break; case SET_REGION_STATE: - if (commands.length < 3) { - showErrorMessage(command + " takes region encoded name and state arguments: e.g. " - + "35f30b0ce922c34bf5c284eff33ba8b3 CLOSING"); - return EXIT_FAILURE; - } - RegionState.State state = RegionState.State.valueOf(commands[2]); - - int replicaId = 0; - String region = commands[1]; - int separatorIndex = commands[1].indexOf(","); - if (separatorIndex > 0) { - region = commands[1].substring(0, separatorIndex); - replicaId = Integer.getInteger(commands[1].substring(separatorIndex + 1)); - } - - if (replicaId > 0) { - System.out.println("Change state for replica reigon " + replicaId + - " for primary region " + region); - } - - try (ClusterConnection connection = connect()) { - checkHBCKSupport(connection, command); - return setRegionState(connection, region, replicaId, state); + if (getFromFile) { + if (commands.length < 2) { + showErrorMessage(command + " takes a list of file names"); + return EXIT_FAILURE; + } + List argList = getFromFiles(Arrays.asList(purgeFirst(commands))); + try (ClusterConnection connection = connect()) { + checkHBCKSupport(connection, command); + for (String line : argList) { + String[] args = formatSetRegionStateCommand(line.split("\\s+")); + if (setRegionState(connection, args) == EXIT_FAILURE) { + showErrorMessage(command + " failed to set " + args); + } + } + } + break; + } else { + String[] args = formatSetRegionStateCommand(purgeFirst(commands)); + try (ClusterConnection connection = connect()) { + checkHBCKSupport(connection, command); + return setRegionState(connection, args); + } } - case FILESYSTEM: try (ClusterConnection connection = connect()) { checkHBCKSupport(connection, command); @@ -1230,6 +1277,31 @@ private static String[] purgeFirst(String[] args) { return result; } + /** + * @return arguements for SET_REGION_STATE command + */ + private String[] formatSetRegionStateCommand(String[] commands) { + if (commands.length < 2) { + showErrorMessage("setRegionState takes region encoded name and state arguments: e.g. " + + "35f30b0ce922c34bf5c284eff33ba8b3 CLOSING"); + return null; + } + Integer replicaId = 0; + String region = commands[0]; + int separatorIndex = commands[0].indexOf(","); + if (separatorIndex > 0) { + region = commands[0].substring(0, separatorIndex); + replicaId = Integer.getInteger(commands[0].substring(separatorIndex + 1)); + } + + if (replicaId > 0) { + System.out.println("Change state for replica reigon " + replicaId + + " for primary region " + region); + } + RegionState.State state = RegionState.State.valueOf(commands[1]); + return new String[]{region, replicaId.toString(), state.name()}; + } + HBCK2(Configuration conf) { super(conf); } diff --git a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java index f3bd73d0a8..d0361b9255 100644 --- a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java +++ b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java @@ -77,6 +77,8 @@ public class TestHBCK2 { private final static String ASSIGNS = "assigns"; private static final String EXTRA_REGIONS_IN_META = "extraRegionsInMeta"; private final static String UNASSIGNS = "unassigns"; + private final static String SET_REGION_STATE = "setRegionState"; + private final static String SET_TABLE_STATE = "setTableState"; @Rule public TestName testName = new TestName(); @@ -122,6 +124,25 @@ public void testSetTableStateInMeta() throws IOException { // Restore the state. state = this.hbck2.setTableState(hbck, TABLE_NAME, state.getState()); assertTrue("Found=" + state.getState(), state.isDisabled()); + + // Test the new method with arg list + String[] args = new String[]{TABLE_NAME.getNameAsString(), "DISABLED"}; + state = this.hbck2.setTableState(hbck, args); + assertTrue("Found=" + state.getState(), state.isEnabled()); + } + } + + @Test + public void testSetTableStateWithInputFiles() throws IOException { + File testFile = new File(TEST_UTIL.getDataTestDir().toString(), "inputForSetTableTest"); + writeStringsToAFile(testFile, new String[]{TABLE_NAME.getNameAsString() + " DISABLED" }); + String result = testRunWithArgs(new String[]{"-i", SET_TABLE_STATE, testFile.toString()}); + assertTrue(result.contains("tableName=TestHBCK2, state=ENABLED")); + + // Restore the state. + try (ClusterConnection connection = this.hbck2.connect(); Hbck hbck = connection.getHbck()) { + TableState state = this.hbck2.setTableState(hbck, TABLE_NAME, TableState.State.ENABLED); + assertTrue("Found=" + state.getState(), state.isDisabled()); } } @@ -193,6 +214,49 @@ public void testSetRegionState() throws IOException { } } + @Test + public void testSetRegionStateWithArgsList() throws IOException { + TEST_UTIL.createTable(REGION_STATES_TABLE_NAME, Bytes.toBytes("family1")); + try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { + List regions = admin.getRegions(REGION_STATES_TABLE_NAME); + RegionInfo info = regions.get(0); + assertEquals(RegionState.State.OPEN, getCurrentRegionState(info)); + String region = info.getEncodedName(); + String[] args = new String[]{region, "0", "CLOSING"}; + try (ClusterConnection connection = this.hbck2.connect()) { + this.hbck2.setRegionState(connection, args); + } + assertEquals(RegionState.State.CLOSING, getCurrentRegionState(info)); + } finally { + TEST_UTIL.deleteTable(REGION_STATES_TABLE_NAME); + } + } + + @Test + public void testSetRegionStateInputFiles() throws IOException { + TEST_UTIL.createTable(REGION_STATES_TABLE_NAME, Bytes.toBytes("family1")); + try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { + List regions = admin.getRegions(REGION_STATES_TABLE_NAME); + String[] input = new String[regions.size()]; + for (int i = 0; i < regions.size(); i++) { + RegionInfo info = regions.get(i); + assertEquals(RegionState.State.OPEN, getCurrentRegionState(info)); + String region = info.getEncodedName(); + input[i] = region + " CLOSING"; + } + + File testFile = new File(TEST_UTIL.getDataTestDir().toString(), "inputForSetRegionStateTest"); + writeStringsToAFile(testFile, input); + testRunWithArgs(new String[]{"-i", SET_REGION_STATE, testFile.toString()}); + + for (RegionInfo info : regions) { + assertEquals(RegionState.State.CLOSING, getCurrentRegionState(info)); + } + } finally { + TEST_UTIL.deleteTable(REGION_STATES_TABLE_NAME); + } + } + @Test public void testSetReplicaRegionState() throws IOException, InterruptedException { TEST_UTIL.createTable(REGION_STATES_TABLE_NAME, Bytes.toBytes("family1")); diff --git a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java index 050a65faeb..ae7cc42082 100644 --- a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java +++ b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java @@ -78,7 +78,8 @@ public void testInputFileOption() throws IOException { @Test (expected=IllegalArgumentException.class) public void testSetRegionStateCommandInvalidState() throws IOException { HBCK2 hbck = new HBCK2(TEST_UTIL.getConfiguration()); - // The 'x' below should cause the IllegalArgumentException. The Options should all be good. + // The 'INVALID_STATE' below should cause the IllegalArgumentException. + // The Options should all be good. hbck.run(new String[]{"setRegionState", "region_encoded", "INVALID_STATE"}); } From 82a48d686282abd3c2656ee1086391c00d050de7 Mon Sep 17 00:00:00 2001 From: Clara Xiong Date: Tue, 5 Apr 2022 09:31:59 -0700 Subject: [PATCH 6/6] README format update --- hbase-hbck2/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hbase-hbck2/README.md b/hbase-hbck2/README.md index 1d9fd5c626..b895195258 100644 --- a/hbase-hbck2/README.md +++ b/hbase-hbck2/README.md @@ -148,7 +148,7 @@ Command: -o,--override override if procedure is running/stuck -r,--recursive bypass parent and its children. SLOW! EXPENSIVE! -w,--lockWait milliseconds to wait before giving up; default=1 - Pass one (or more) procedure 'pid's to skip to procedure finish. Parent + Pass one (or more) procedure 'pid's to skip to procedure finish. Parent of bypassed procedure will also be skipped to the finish. Entities will be left in an inconsistent state and will require manual fixup. May need Master restart to clear locks still held. Bypass fails if @@ -243,7 +243,7 @@ Command: $ HBCK2 -i replication fileName1 fileName2 reportMissingRegionsInMeta ... - To be used when regions missing from hbase:meta but directories + To be used when regions missing from hbase:meta but directories are present still in HDFS. Can happen if user has run _hbck1_ 'OfflineMetaRepair' against an hbase-2.x cluster. This is a CHECK only method, designed for reporting purposes and doesn't perform any