From 232e485cea0f8726cf6fb8c518deef7c22aed7e7 Mon Sep 17 00:00:00 2001 From: Wellington Chevreuil Date: Mon, 1 Apr 2019 15:49:39 +0100 Subject: [PATCH] HBASE-22143 - HBCK2 setRegionState command --- .../src/main/java/org/apache/hbase/HBCK2.java | 57 +++++++++++++++++++ .../test/java/org/apache/hbase/TestHBCK2.java | 26 +++++++++ 2 files changed, 83 insertions(+) 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 e9089e8..0e5ccf0 100644 --- a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java +++ b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java @@ -26,16 +26,25 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.ClusterMetrics; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.ClusterConnection; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.Hbck; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.RegionInfo; +import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.TableState; +import org.apache.hadoop.hbase.master.RegionState; +import org.apache.hadoop.hbase.regionserver.HRegionFileSystem; +import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.VersionInfo; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; @@ -50,6 +59,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.List; @@ -77,6 +87,7 @@ public class HBCK2 extends Configured implements Tool { private static final String UNASSIGNS = "unassigns"; private static final String BYPASS = "bypass"; private static final String VERSION = "version"; + private static final String SET_REGION_STATE = "setRegionState"; private Configuration conf; private static final String TWO_POINT_ONE = "2.1.0"; private static final String MININUM_VERSION = "2.0.3"; @@ -120,6 +131,27 @@ public class HBCK2 extends Configured implements Tool { } } + RegionState.State setRegionState(String regionPath, RegionState.State newState) + throws IOException { + FileSystem fs = FileSystem.get(getConf()); + RegionInfo info = HRegionFileSystem.loadRegionInfoFileContent(fs, new Path(regionPath)); + RegionState.State currentState = null; + try (ClusterConnection conn = + (ClusterConnection) ConnectionFactory.createConnection(getConf())) { + Result result = MetaTableAccessor.getRegionResult(conn, info.getRegionName()); + byte[] currentStateValue = result.getValue(HConstants.CATALOG_FAMILY, + HConstants.STATE_QUALIFIER); + currentState = RegionState.State.valueOf(Bytes.toString(currentStateValue)); + Put put = MetaTableAccessor.makePutFromRegionInfo(info, System.currentTimeMillis()); + put.addColumn(HConstants.CATALOG_FAMILY, HConstants.STATE_QUALIFIER, + Bytes.toBytes(newState.name())); + List puts = new ArrayList<>(); + puts.add(put); + MetaTableAccessor.putsToMetaTable(conn, puts); + } + return currentState; + } + List assigns(String [] args) throws IOException { Options options = new Options(); Option override = Option.builder("o").longOpt("override").build(); @@ -272,6 +304,22 @@ public class HBCK2 extends Configured implements Tool { writer.println(" $ HBCK2 setTableState users ENABLED"); writer.println(" Returns whatever the previous table state was."); writer.println(); + writer.println(" " + SET_REGION_STATE + " "); + writer.println(" Possible region states: " + Arrays.stream(RegionState.State.values()). + map(i -> i.toString()).collect(Collectors.joining(", "))); + writer.println(" WARNING: This is a very risky option intended for use as last resource."); + writer.println(" Example scenarios for this is when unassings/assigns can't move forward "); + writer.println(" due region being on an inconsistent state in META. For example, "); + writer.println(" 'unassigns' command can only proceed "); + writer.println(" if passed in region is in one of following states: "); + writer.println(" [SPLITTING|SPLIT|MERGING|OPEN|CLOSING]"); + writer.println(" Before manually setting a region state with this command,"); + writer.println(" please certify that this region is not being handled "); + writer.println(" a running procedure, such as Assign or Split. "); + writer.println(" An example setting region 'de00010733901a05f5a2a3a382e27dd4' to CLOSING:"); + writer.println(" $ HBCK2 setRegionState de00010733901a05f5a2a3a382e27dd4 CLOSING"); + writer.println(" Returns whatever the previous region state was."); + writer.println(); writer.close(); return sw.toString(); @@ -403,6 +451,15 @@ public class HBCK2 extends Configured implements Tool { System.out.println(toString(unassigns(purgeFirst(commands)))); break; + case SET_REGION_STATE: + if(commands.length < 3){ + usage(options, command + " takes region path and state arguments: e.g. " + + "/hbase/data/default/user/35f30b0ce922c34bf5c284eff33ba8b3 CLOSING"); + return EXIT_FAILURE; + } + System.out.println(setRegionState(commands[1], RegionState.State.valueOf(commands[2]))); + break; + default: usage(options, "Unsupported command: " + command); return EXIT_FAILURE; 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 e902275..0762781 100644 --- a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java +++ b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java @@ -19,9 +19,12 @@ package org.apache.hbase; import junit.framework.TestCase; import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.RegionInfo; +import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.TableState; import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.util.Bytes; @@ -132,6 +135,29 @@ public class TestHBCK2 { } } + @Test + public void testSetRegionState() throws IOException { + try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { + List regions = admin.getRegions(TABLE_NAME); + RegionInfo info = regions.get(0); + assertEquals(RegionState.State.OPEN, getCurrentRegionState(info)); + HBCK2 hbck = new HBCK2(TEST_UTIL.getConfiguration()); + String regionPath = TEST_UTIL.getDefaultRootDirPath().toString() + "/data/default/" + + TABLE_NAME.getNameAsString() + "/" + info.getEncodedName(); + hbck.setRegionState(regionPath, RegionState.State.CLOSING); + assertEquals(RegionState.State.CLOSING, getCurrentRegionState(info)); + } + + } + + private RegionState.State getCurrentRegionState(RegionInfo regionInfo) throws IOException{ + Result result = MetaTableAccessor.getRegionResult(TEST_UTIL.getConnection(), + regionInfo.getRegionName()); + byte[] currentStateValue = result.getValue(HConstants.CATALOG_FAMILY, + HConstants.STATE_QUALIFIER); + return RegionState.State.valueOf(Bytes.toString(currentStateValue)); + } + private void waitOnPids(List pids) { for (Long pid: pids) { while (!TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(). -- 2.17.2 (Apple Git-113)