Skip to content
Permalink
Browse files
HBASE-26338 hbck2 setRegionState cannot set replica region state (#94)
Signed-off-by: Wellington Ramos Chevreuil <wchevreuil@apache.org>
  • Loading branch information
huaxiangsun committed Oct 11, 2021
1 parent d3ad075 commit 98bb5849f86ba531bac3928fb63f04576795fc53
Showing 2 changed files with 92 additions and 7 deletions.
@@ -22,7 +22,9 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -89,6 +91,9 @@ public class HBCK2 extends Configured implements org.apache.hadoop.util.Tool {
private static final Logger LOG = LoggerFactory.getLogger(HBCK2.class);
private static final int EXIT_SUCCESS = 0;
static final int EXIT_FAILURE = 1;
/** The delimiter for meta columns for replicaIds &gt; 0 */
private static final char META_REPLICA_ID_DELIMITER = '_';

// Commands
private static final String SET_TABLE_STATE = "setTableState";
private static final String ASSIGNS = "assigns";
@@ -167,6 +172,18 @@ void checkFunctionSupported(ClusterConnection connection, String cmd) throws IOE
}
}

public static byte[] getRegionStateColumn(int replicaId) {
try {
return replicaId == 0 ? HConstants.STATE_QUALIFIER
: (HConstants.STATE_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
+ String.format(RegionInfo.REPLICA_ID_FORMAT,
replicaId)).getBytes(StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
// should never happen!
throw new IllegalArgumentException("UTF8 decoding is not supported", e);
}
}

TableState setTableState(Hbck hbck, TableName tableName, TableState.State state)
throws IOException {
return hbck.setTableStateInMeta(new TableState(tableName, state));
@@ -175,6 +192,12 @@ TableState setTableState(Hbck hbck, TableName tableName, TableState.State state)
int setRegionState(ClusterConnection connection, String region,
RegionState.State newState)
throws IOException {
return setRegionState(connection, region, 0, newState);
}

int setRegionState(ClusterConnection connection, String region, int replicaId,
RegionState.State newState)
throws IOException {
if (newState == null) {
throw new IllegalArgumentException("State can't be null.");
}
@@ -186,19 +209,27 @@ int setRegionState(ClusterConnection connection, String region,
Result result = table.getScanner(scan).next();
if (result != null) {
byte[] currentStateValue = result.getValue(HConstants.CATALOG_FAMILY,
HConstants.STATE_QUALIFIER);
getRegionStateColumn(replicaId));
if (currentStateValue == null) {
System.out.println("WARN: Region state info on meta was NULL");
} else {
currentState = RegionState.State.valueOf(
org.apache.hadoop.hbase.util.Bytes.toString(currentStateValue));
org.apache.hadoop.hbase.util.Bytes.toString(currentStateValue));
}
Put put = new Put(result.getRow());
put.addColumn(HConstants.CATALOG_FAMILY, HConstants.STATE_QUALIFIER,
org.apache.hadoop.hbase.util.Bytes.toBytes(newState.name()));
put.addColumn(HConstants.CATALOG_FAMILY, getRegionStateColumn(replicaId),
org.apache.hadoop.hbase.util.Bytes.toBytes(newState.name()));
table.put(put);
System.out.println("Changed region " + region + " STATE from "
+ currentState + " to " + newState);

if (replicaId == 0) {
System.out.println("Changed region " + region + " STATE from "
+ currentState + " to " + newState);
} else {
System.out.println("Changed STATE for replica reigon " + replicaId +
" of primary region " + region +
"from " + currentState + " to " + newState);
}

return EXIT_SUCCESS;
} else {
System.out.println("ERROR: Could not find region " + region + " in meta.");
@@ -626,6 +657,9 @@ private static void usageReportMissingRegionsInMeta(PrintWriter writer) {

private static void usageSetRegionState(PrintWriter writer) {
writer.println(" " + SET_REGION_STATE + " <ENCODED_REGIONNAME> <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 + " <PRIMARY_ENCODED_REGIONNAME>,<replicaId> <STATE>");
writer.println(" Possible region states:");
writer.println(" OFFLINE, OPENING, OPEN, CLOSING, CLOSED, SPLITTING, SPLIT,");
writer.println(" FAILED_OPEN, FAILED_CLOSE, MERGING, MERGED, SPLITTING_NEW,");
@@ -875,9 +909,23 @@ private int doCommandLine(CommandLine commandLine, Options options) throws IOExc
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, commands[1], state);
return setRegionState(connection, region, replicaId, state);
}

case FILESYSTEM:
@@ -186,6 +186,30 @@ public void testSetRegionState() throws IOException {
}
}

@Test
public void testSetReplicaRegionState() throws IOException, InterruptedException {
TEST_UTIL.createTable(REGION_STATES_TABLE_NAME, Bytes.toBytes("family1"));
try {
Admin admin = TEST_UTIL.getConnection().getAdmin();
TEST_UTIL.setReplicas(admin, REGION_STATES_TABLE_NAME, 2);
List<RegionInfo> regions = admin.getRegions(REGION_STATES_TABLE_NAME);
assertEquals(regions.size(), 2);
assertEquals(regions.get(0).getReplicaId(), 0);
assertEquals(regions.get(1).getReplicaId(), 1);
RegionInfo primaryRegionInfo = regions.get(0);
int replicaId = regions.get(1).getReplicaId();
assertEquals(RegionState.State.OPEN, getCurrentRegionState(regions.get(0), replicaId));
String primaryRegion = primaryRegionInfo.getEncodedName();
try (ClusterConnection connection = this.hbck2.connect()) {
this.hbck2.setRegionState(connection, primaryRegion, regions.get(1).getReplicaId(),
RegionState.State.CLOSING);
}
assertEquals(RegionState.State.CLOSING, getCurrentRegionState(primaryRegionInfo, replicaId));
} finally {
TEST_UTIL.deleteTable(REGION_STATES_TABLE_NAME);
}
}

@Test
public void testSetRegionStateInvalidRegion() throws IOException {
try (ClusterConnection connection = this.hbck2.connect()) {
@@ -390,6 +414,19 @@ private RegionState.State getCurrentRegionState(RegionInfo regionInfo) throws IO
: null;
}

private RegionState.State getCurrentRegionState(RegionInfo primary, int replicaId)
throws IOException {
Table metaTable = TEST_UTIL.getConnection().getTable(TableName.valueOf("hbase:meta"));
Get get = new Get(primary.getRegionName());
get.addColumn(HConstants.CATALOG_FAMILY, HBCK2.getRegionStateColumn(replicaId));
Result result = metaTable.get(get);
byte[] currentStateValue = result.getValue(HConstants.CATALOG_FAMILY,
HBCK2.getRegionStateColumn(replicaId));
return currentStateValue != null ?
RegionState.State.valueOf(Bytes.toString(currentStateValue))
: null;
}

private void waitOnPids(List<Long> pids) {
for (Long pid: pids) {
while (!TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor().

0 comments on commit 98bb584

Please sign in to comment.