HBASE-23117: Bad enum in hbase:meta info:state column can fail loadMeta and stop startup (#867)
* Handling the BAD value in info:state columns in hbase:meta * Adding a unit test and region encoded name in the LOG * Adding a null check for region state to complete the test scenario and fixing the nit Signed-off-by: Wellington Chevreuil <wchevreuil@apache.org> Signed-off-by: GuangxuCheng <guangxucheng@gmail.com> Signed-off-by: stack <stack@apache.org>
This commit is contained in:
parent
b99f58304e
commit
0d7a6b9725
|
@ -132,7 +132,7 @@ public class RegionStateStore {
|
||||||
if (regionInfo == null) continue;
|
if (regionInfo == null) continue;
|
||||||
|
|
||||||
final int replicaId = regionInfo.getReplicaId();
|
final int replicaId = regionInfo.getReplicaId();
|
||||||
final State state = getRegionState(result, replicaId);
|
final State state = getRegionState(result, replicaId, regionInfo);
|
||||||
|
|
||||||
final ServerName lastHost = hrl.getServerName();
|
final ServerName lastHost = hrl.getServerName();
|
||||||
final ServerName regionLocation = getRegionServer(result, replicaId);
|
final ServerName regionLocation = getRegionServer(result, replicaId);
|
||||||
|
@ -347,13 +347,22 @@ public class RegionStateStore {
|
||||||
* @return the region state, or null if unknown.
|
* @return the region state, or null if unknown.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static State getRegionState(final Result r, int replicaId) {
|
public static State getRegionState(final Result r, int replicaId, RegionInfo regionInfo) {
|
||||||
Cell cell = r.getColumnLatestCell(HConstants.CATALOG_FAMILY, getStateColumn(replicaId));
|
Cell cell = r.getColumnLatestCell(HConstants.CATALOG_FAMILY, getStateColumn(replicaId));
|
||||||
if (cell == null || cell.getValueLength() == 0) {
|
if (cell == null || cell.getValueLength() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return State.valueOf(Bytes.toString(cell.getValueArray(), cell.getValueOffset(),
|
|
||||||
cell.getValueLength()));
|
String state = Bytes.toString(cell.getValueArray(), cell.getValueOffset(),
|
||||||
|
cell.getValueLength());
|
||||||
|
try {
|
||||||
|
return State.valueOf(state);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOG.warn("BAD value {} in hbase:meta info:state column for region {} , " +
|
||||||
|
"Consider using HBCK2 setRegionState ENCODED_REGION_NAME STATE",
|
||||||
|
state, regionInfo.getEncodedName());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getStateColumn(int replicaId) {
|
private static byte[] getStateColumn(int replicaId) {
|
||||||
|
|
|
@ -3606,7 +3606,7 @@ public class HBaseTestingUtility extends HBaseZKTestingUtility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RegionStateStore.getRegionState(r,
|
if (RegionStateStore.getRegionState(r,
|
||||||
info.getReplicaId()) != RegionState.State.OPEN) {
|
info.getReplicaId(), info) != RegionState.State.OPEN) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,20 +19,26 @@ package org.apache.hadoop.hbase.master.assignment;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.ServerName;
|
import org.apache.hadoop.hbase.ServerName;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
import org.apache.hadoop.hbase.client.RegionInfo;
|
import org.apache.hadoop.hbase.client.RegionInfo;
|
||||||
import org.apache.hadoop.hbase.client.Result;
|
import org.apache.hadoop.hbase.client.Result;
|
||||||
|
import org.apache.hadoop.hbase.client.Table;
|
||||||
import org.apache.hadoop.hbase.master.RegionState;
|
import org.apache.hadoop.hbase.master.RegionState;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
import org.apache.hadoop.hbase.testclassification.MasterTests;
|
import org.apache.hadoop.hbase.testclassification.MasterTests;
|
||||||
import org.apache.hadoop.hbase.testclassification.MediumTests;
|
import org.apache.hadoop.hbase.testclassification.MediumTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
|
@ -84,6 +90,39 @@ public class TestRegionStateStore {
|
||||||
assertTrue("Visitor has not been called.", visitorCalled.get());
|
assertTrue("Visitor has not been called.", visitorCalled.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVisitMetaForBadRegionState() throws Exception {
|
||||||
|
final TableName tableName = TableName.valueOf("testVisitMetaForBadRegionState");
|
||||||
|
util.createTable(tableName, "cf");
|
||||||
|
final List<HRegion> regions = util.getHBaseCluster().getRegions(tableName);
|
||||||
|
final String encodedName = regions.get(0).getRegionInfo().getEncodedName();
|
||||||
|
final RegionStateStore regionStateStore = util.getHBaseCluster().getMaster().
|
||||||
|
getAssignmentManager().getRegionStateStore();
|
||||||
|
|
||||||
|
// add the BAD_STATE which does not exist in enum RegionState.State
|
||||||
|
Put put = new Put(regions.get(0).getRegionInfo().getRegionName(),
|
||||||
|
EnvironmentEdgeManager.currentTime());
|
||||||
|
put.addColumn(HConstants.CATALOG_FAMILY, HConstants.STATE_QUALIFIER,
|
||||||
|
Bytes.toBytes("BAD_STATE"));
|
||||||
|
|
||||||
|
try (Table table = util.getConnection().getTable(TableName.META_TABLE_NAME)) {
|
||||||
|
table.put(put);
|
||||||
|
}
|
||||||
|
|
||||||
|
final AtomicBoolean visitorCalled = new AtomicBoolean(false);
|
||||||
|
regionStateStore.visitMetaForRegion(encodedName, new RegionStateStore.RegionStateVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visitRegionState(Result result, RegionInfo regionInfo,
|
||||||
|
RegionState.State state, ServerName regionLocation,
|
||||||
|
ServerName lastHost, long openSeqNum) {
|
||||||
|
assertEquals(encodedName, regionInfo.getEncodedName());
|
||||||
|
assertNull(state);
|
||||||
|
visitorCalled.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertTrue("Visitor has not been called.", visitorCalled.get());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVisitMetaForRegionNonExistingRegion() throws Exception {
|
public void testVisitMetaForRegionNonExistingRegion() throws Exception {
|
||||||
final String encodedName = "fakeencodedregionname";
|
final String encodedName = "fakeencodedregionname";
|
||||||
|
|
Loading…
Reference in New Issue