Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HBASE-23117: Bad enum in hbase:meta info:state column can fail loadMeta and stop startup #867

Merged
merged 3 commits into from
Nov 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private void visitMetaEntry(final RegionStateVisitor visitor, final Result resul
if (regionInfo == null) continue;

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 regionLocation = getRegionServer(result, replicaId);
Expand Down Expand Up @@ -347,13 +347,22 @@ private static byte[] getServerNameColumn(int replicaId) {
* @return the region state, or null if unknown.
*/
@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));
if (cell == null || cell.getValueLength() == 0) {
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3654,7 +3654,7 @@ public boolean evaluate() throws IOException {
}
}
if (RegionStateStore.getRegionState(r,
info.getReplicaId()) != RegionState.State.OPEN) {
info.getReplicaId(), info) != RegionState.State.OPEN) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,26 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.ServerName;
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.Result;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.testclassification.MasterTests;
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.Before;
import org.junit.ClassRule;
Expand Down Expand Up @@ -84,6 +90,39 @@ public void visitRegionState(Result result, RegionInfo regionInfo, RegionState.S
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());
wchevreuil marked this conversation as resolved.
Show resolved Hide resolved
assertNull(state);
visitorCalled.set(true);
}
});
assertTrue("Visitor has not been called.", visitorCalled.get());
}

@Test
public void testVisitMetaForRegionNonExistingRegion() throws Exception {
final String encodedName = "fakeencodedregionname";
Expand Down