HBASE-18796 Admin#isTableAvailable returns incorrect result before daughter regions are opened

Signed-off-by: Andrew Purtell <apurtell@apache.org>
This commit is contained in:
Abhishek Singh Chouhan 2017-09-18 14:56:14 +05:30 committed by Andrew Purtell
parent 539fce3440
commit 2845ddaf9e
3 changed files with 114 additions and 2 deletions

View File

@ -1340,8 +1340,8 @@ public class MetaTableAccessor {
Put putA = makePutFromRegionInfo(splitA);
Put putB = makePutFromRegionInfo(splitB);
addLocation(putA, sn, 1, -1, splitA.getReplicaId()); //new regions, openSeqNum = 1 is fine.
addLocation(putB, sn, 1, -1, splitB.getReplicaId());
addSequenceNum(putA, 1, -1, splitA.getReplicaId()); //new regions, openSeqNum = 1 is fine.
addSequenceNum(putB, 1, -1, splitB.getReplicaId());
// Add empty locations for region replicas of daughters so that number of replicas can be
// cached whenever the primary region is looked up from meta
@ -1612,6 +1612,15 @@ public class MetaTableAccessor {
return p;
}
public static Put addSequenceNum(final Put p, long openSeqNum, long time, int replicaId) {
if (time <= 0) {
time = EnvironmentEdgeManager.currentTime();
}
p.addImmutable(HConstants.CATALOG_FAMILY, getSeqNumColumn(replicaId), time,
Bytes.toBytes(openSeqNum));
return p;
}
/**
* Get replication position for a peer in a region.
* @param connection connection we're using

View File

@ -644,5 +644,46 @@ public class TestMetaTableAccessor {
assertTrue(prevCalls < scheduler.numPriorityCalls);
}
}
@Test
public void testEmptyMetaDaughterLocationDuringSplit() throws IOException {
long regionId = System.currentTimeMillis();
ServerName serverName0 = ServerName.valueOf("foo", 60010, random.nextLong());
HRegionInfo parent = new HRegionInfo(TableName.valueOf("table_foo"), HConstants.EMPTY_START_ROW,
HConstants.EMPTY_END_ROW, false, regionId, 0);
HRegionInfo splitA = new HRegionInfo(TableName.valueOf("table_foo"), HConstants.EMPTY_START_ROW,
Bytes.toBytes("a"), false, regionId + 1, 0);
HRegionInfo splitB = new HRegionInfo(TableName.valueOf("table_foo"), Bytes.toBytes("a"),
HConstants.EMPTY_END_ROW, false, regionId + 1, 0);
Table meta = MetaTableAccessor.getMetaHTable(connection);
try {
List<HRegionInfo> regionInfos = Lists.newArrayList(parent);
MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3);
MetaTableAccessor.splitRegion(connection, parent, splitA, splitB, serverName0, 3, false);
Get get1 = new Get(splitA.getRegionName());
Result resultA = meta.get(get1);
Cell serverCellA = resultA.getColumnLatestCell(HConstants.CATALOG_FAMILY,
MetaTableAccessor.getServerColumn(splitA.getReplicaId()));
Cell startCodeCellA = resultA.getColumnLatestCell(HConstants.CATALOG_FAMILY,
MetaTableAccessor.getStartCodeColumn(splitA.getReplicaId()));
assertNull(serverCellA);
assertNull(startCodeCellA);
Get get2 = new Get(splitA.getRegionName());
Result resultB = meta.get(get2);
Cell serverCellB = resultB.getColumnLatestCell(HConstants.CATALOG_FAMILY,
MetaTableAccessor.getServerColumn(splitB.getReplicaId()));
Cell startCodeCellB = resultB.getColumnLatestCell(HConstants.CATALOG_FAMILY,
MetaTableAccessor.getStartCodeColumn(splitB.getReplicaId()));
assertNull(serverCellB);
assertNull(startCodeCellB);
} finally {
if (meta != null) {
meta.close();
}
}
}
}

View File

@ -136,6 +136,11 @@ public class TestEndToEndSplitTransaction {
regions.getSecond().getRegionInfo());
}
// first daughter second
if (split.useZKForAssignment) {
server.postOpenDeployTasks(regions.getFirst());
}
// Add to online regions
server.addToOnlineRegions(regions.getSecond());
// THIS is the crucial point:
@ -161,6 +166,63 @@ public class TestEndToEndSplitTransaction {
}
}
@Test
public void testTableAvailableWhileSplitting() throws Exception {
TableName tableName = TableName.valueOf("TestTableAvailableWhileSplitting");
byte[] familyName = Bytes.toBytes("fam");
try (HTable ht = TEST_UTIL.createTable(tableName, familyName)) {
TEST_UTIL.loadTable(ht, familyName, false);
}
Admin admin = TEST_UTIL.getHBaseAdmin();
HRegionServer server = TEST_UTIL.getHBaseCluster().getRegionServer(0);
byte[] splitRow = Bytes.toBytes("lll");
try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
byte[] regionName = conn.getRegionLocator(tableName).getRegionLocation(splitRow)
.getRegionInfo().getRegionName();
Region region = server.getRegion(regionName);
SplitTransactionImpl split = new SplitTransactionImpl((HRegion) region, splitRow);
split.prepare();
assertTrue(admin.isTableAvailable(tableName));
// 1. phase I
PairOfSameType<Region> regions = split.createDaughters(server, server, null);
// Parent should be offline at this stage and daughters not yet open
assertFalse(admin.isTableAvailable(tableName));
// passing null as services prevents final step of postOpenDeployTasks
// 2, most of phase II
split.openDaughters(server, null, regions.getFirst(), regions.getSecond());
assertFalse(admin.isTableAvailable(tableName));
// Finish openeing daughters
// 2nd daughter first
if (split.useZKForAssignment) {
server.postOpenDeployTasks(regions.getSecond());
} else {
server.reportRegionStateTransition(
RegionServerStatusProtos.RegionStateTransition.TransitionCode.SPLIT,
region.getRegionInfo(), regions.getFirst().getRegionInfo(),
regions.getSecond().getRegionInfo());
}
// first daughter second
if (split.useZKForAssignment) {
server.postOpenDeployTasks(regions.getFirst());
}
// After postOpenDeploy daughters should have location in meta
assertTrue(admin.isTableAvailable(tableName));
server.addToOnlineRegions(regions.getSecond());
server.addToOnlineRegions(regions.getFirst());
assertTrue(admin.isTableAvailable(tableName));
} finally {
if (admin != null) {
admin.close();
}
}
}
/**
* attempt to locate the region and perform a get and scan
* @return True if successful, False otherwise.