Skip to content

Commit 237229c

Browse files
committed
HBASE-22707 [HBCK2] MasterRpcServices assigns method should try to reload regions from meta if the passed regions isn't found under AssignmentManager RegionsStateStore
Signed-off-by: stack <stack@apache.org>
1 parent 8cfc46d commit 237229c

File tree

7 files changed

+285
-45
lines changed

7 files changed

+285
-45
lines changed

hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
import org.apache.hadoop.hbase.exceptions.DeserializationException;
6060
import org.apache.hadoop.hbase.filter.Filter;
6161
import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
62+
import org.apache.hadoop.hbase.filter.RowFilter;
63+
import org.apache.hadoop.hbase.filter.SubstringComparator;
6264
import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
6365
import org.apache.hadoop.hbase.ipc.ServerRpcController;
6466
import org.apache.hadoop.hbase.master.RegionState;
@@ -372,6 +374,25 @@ public static Result getRegionResult(Connection connection,
372374
return get(getMetaHTable(connection), get);
373375
}
374376

377+
/**
378+
* Scans META table for a row whose key contains the specified <B>regionEncodedName</B>,
379+
* returning a single related <code>Result</code> instance if any row is found, null otherwise.
380+
*
381+
* @param connection the connection to query META table.
382+
* @param regionEncodedName the region encoded name to look for at META.
383+
* @return <code>Result</code> instance with the row related info in META, null otherwise.
384+
* @throws IOException if any errors occur while querying META.
385+
*/
386+
public static Result scanByRegionEncodedName(Connection connection,
387+
String regionEncodedName) throws IOException {
388+
RowFilter rowFilter = new RowFilter(CompareOperator.EQUAL,
389+
new SubstringComparator(regionEncodedName));
390+
Scan scan = getMetaScan(connection, 1);
391+
scan.setFilter(rowFilter);
392+
ResultScanner resultScanner = getMetaHTable(connection).getScanner(scan);
393+
return resultScanner.next();
394+
}
395+
375396
/**
376397
* Get regions from the merge qualifier of the specified merged region
377398
* @return null if it doesn't contain merge qualifier, else two merge regions

hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2417,7 +2417,9 @@ private RegionInfo getRegionInfo(HBaseProtos.RegionSpecifier rs) throws UnknownR
24172417
String encodedRegionName = Bytes.toString(rs.getValue().toByteArray());
24182418
RegionState regionState = this.master.getAssignmentManager().getRegionStates().
24192419
getRegionState(encodedRegionName);
2420-
ri = regionState == null? null: regionState.getRegion();
2420+
ri = regionState == null ?
2421+
this.master.getAssignmentManager().loadRegionFromMeta(encodedRegionName) :
2422+
regionState.getRegion();
24212423
break;
24222424
default:
24232425
break;

hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,51 +1383,82 @@ public void processOfflineRegions() {
13831383
}
13841384
}
13851385

1386-
private void loadMeta() throws IOException {
1387-
// TODO: use a thread pool
1388-
regionStateStore.visitMeta(new RegionStateStore.RegionStateVisitor() {
1389-
@Override
1390-
public void visitRegionState(Result result, final RegionInfo regionInfo, final State state,
1391-
final ServerName regionLocation, final ServerName lastHost, final long openSeqNum) {
1392-
if (state == null && regionLocation == null && lastHost == null &&
1393-
openSeqNum == SequenceId.NO_SEQUENCE_ID) {
1394-
// This is a row with nothing in it.
1395-
LOG.warn("Skipping empty row={}", result);
1396-
return;
1397-
}
1398-
State localState = state;
1399-
if (localState == null) {
1400-
// No region state column data in hbase:meta table! Are I doing a rolling upgrade from
1401-
// hbase1 to hbase2? Am I restoring a SNAPSHOT or otherwise adding a region to hbase:meta?
1402-
// In any of these cases, state is empty. For now, presume OFFLINE but there are probably
1403-
// cases where we need to probe more to be sure this correct; TODO informed by experience.
1404-
LOG.info(regionInfo.getEncodedName() + " regionState=null; presuming " + State.OFFLINE);
1405-
localState = State.OFFLINE;
1406-
}
1407-
RegionStateNode regionNode = regionStates.getOrCreateRegionStateNode(regionInfo);
1408-
// Do not need to lock on regionNode, as we can make sure that before we finish loading
1409-
// meta, all the related procedures can not be executed. The only exception is for meta
1410-
// region related operations, but here we do not load the informations for meta region.
1411-
regionNode.setState(localState);
1412-
regionNode.setLastHost(lastHost);
1413-
regionNode.setRegionLocation(regionLocation);
1414-
regionNode.setOpenSeqNum(openSeqNum);
1415-
1416-
// Note: keep consistent with other methods, see region(Opening|Opened|Closing)
1417-
// RIT/ServerCrash handling should take care of the transiting regions.
1418-
if (localState.matches(State.OPEN, State.OPENING, State.CLOSING, State.SPLITTING,
1419-
State.MERGING)) {
1420-
assert regionLocation != null : "found null region location for " + regionNode;
1421-
regionStates.addRegionToServer(regionNode);
1422-
} else if (localState == State.OFFLINE || regionInfo.isOffline()) {
1423-
regionStates.addToOfflineRegions(regionNode);
1424-
}
1425-
if (regionNode.getProcedure() != null) {
1426-
regionNode.getProcedure().stateLoaded(AssignmentManager.this, regionNode);
1427-
}
1386+
/* AM internal RegionStateStore.RegionStateVisitor implementation. To be used when
1387+
* scanning META table for region rows, using RegionStateStore utility methods. RegionStateStore
1388+
* methods will convert Result into proper RegionInfo instances, but those would still need to be
1389+
* added into AssignmentManager.regionStates in-memory cache.
1390+
* RegionMetaLoadingVisitor.visitRegionState method provides the logic for adding RegionInfo
1391+
* instances as loaded from latest META scan into AssignmentManager.regionStates.
1392+
*/
1393+
private class RegionMetaLoadingVisitor implements RegionStateStore.RegionStateVisitor {
1394+
1395+
@Override
1396+
public void visitRegionState(Result result, final RegionInfo regionInfo, final State state,
1397+
final ServerName regionLocation, final ServerName lastHost, final long openSeqNum) {
1398+
if (state == null && regionLocation == null && lastHost == null &&
1399+
openSeqNum == SequenceId.NO_SEQUENCE_ID) {
1400+
// This is a row with nothing in it.
1401+
LOG.warn("Skipping empty row={}", result);
1402+
return;
14281403
}
1429-
});
1404+
State localState = state;
1405+
if (localState == null) {
1406+
// No region state column data in hbase:meta table! Are I doing a rolling upgrade from
1407+
// hbase1 to hbase2? Am I restoring a SNAPSHOT or otherwise adding a region to hbase:meta?
1408+
// In any of these cases, state is empty. For now, presume OFFLINE but there are probably
1409+
// cases where we need to probe more to be sure this correct; TODO informed by experience.
1410+
LOG.info(regionInfo.getEncodedName() + " regionState=null; presuming " + State.OFFLINE);
1411+
localState = State.OFFLINE;
1412+
}
1413+
RegionStateNode regionNode = regionStates.getOrCreateRegionStateNode(regionInfo);
1414+
// Do not need to lock on regionNode, as we can make sure that before we finish loading
1415+
// meta, all the related procedures can not be executed. The only exception is for meta
1416+
// region related operations, but here we do not load the informations for meta region.
1417+
regionNode.setState(localState);
1418+
regionNode.setLastHost(lastHost);
1419+
regionNode.setRegionLocation(regionLocation);
1420+
regionNode.setOpenSeqNum(openSeqNum);
1421+
1422+
// Note: keep consistent with other methods, see region(Opening|Opened|Closing)
1423+
// RIT/ServerCrash handling should take care of the transiting regions.
1424+
if (localState.matches(State.OPEN, State.OPENING, State.CLOSING, State.SPLITTING,
1425+
State.MERGING)) {
1426+
assert regionLocation != null : "found null region location for " + regionNode;
1427+
regionStates.addRegionToServer(regionNode);
1428+
} else if (localState == State.OFFLINE || regionInfo.isOffline()) {
1429+
regionStates.addToOfflineRegions(regionNode);
1430+
}
1431+
if (regionNode.getProcedure() != null) {
1432+
regionNode.getProcedure().stateLoaded(AssignmentManager.this, regionNode);
1433+
}
1434+
}
1435+
};
1436+
1437+
/**
1438+
* Query META if the given <code>RegionInfo</code> exists, adding to
1439+
* <code>AssignmentManager.regionStateStore</code> cache if the region is found in META.
1440+
* @param regionEncodedName encoded name for the region to be loaded from META into
1441+
* <code>AssignmentManager.regionStateStore</code> cache
1442+
* @return <code>RegionInfo</code> instance for the given region if it is present in META
1443+
* and got successfully loaded into <code>AssignmentManager.regionStateStore</code>
1444+
* cache, <b>null</b> otherwise.
1445+
* @throws UnknownRegionException if any errors occur while querying meta.
1446+
*/
1447+
public RegionInfo loadRegionFromMeta(String regionEncodedName) throws UnknownRegionException {
1448+
try {
1449+
RegionMetaLoadingVisitor visitor = new RegionMetaLoadingVisitor();
1450+
regionStateStore.visitMetaForRegion(regionEncodedName, visitor);
1451+
return regionStates.getRegionState(regionEncodedName) == null ? null :
1452+
regionStates.getRegionState(regionEncodedName).getRegion();
1453+
} catch(IOException e) {
1454+
LOG.error("Error trying to load region {} from META", regionEncodedName, e);
1455+
throw new UnknownRegionException("Error while trying load region from meta");
1456+
}
1457+
}
14301458

1459+
private void loadMeta() throws IOException {
1460+
// TODO: use a thread pool
1461+
regionStateStore.visitMeta(new RegionMetaLoadingVisitor());
14311462
// every assignment is blocked until meta is loaded.
14321463
wakeMetaLoadedEvent();
14331464
}

hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStateStore.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,23 @@ public boolean visit(final Result r) throws IOException {
9696
});
9797
}
9898

99+
/**
100+
* Queries META table for the passed region encoded name,
101+
* delegating action upon results to the <code>RegionStateVisitor</code>
102+
* passed as second parameter.
103+
* @param regionEncodedName encoded name for the Region we want to query META for.
104+
* @param visitor The <code>RegionStateVisitor</code> instance to react over the query results.
105+
* @throws IOException If some error occurs while querying META or parsing results.
106+
*/
107+
public void visitMetaForRegion(final String regionEncodedName, final RegionStateVisitor visitor)
108+
throws IOException {
109+
Result result = MetaTableAccessor.
110+
scanByRegionEncodedName(master.getConnection(), regionEncodedName);
111+
if (result != null) {
112+
visitMetaEntry(visitor, result);
113+
}
114+
}
115+
99116
private void visitMetaEntry(final RegionStateVisitor visitor, final Result result)
100117
throws IOException {
101118
final RegionLocations rl = MetaTableAccessor.getRegionLocations(result);

hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.apache.hadoop.hbase.ipc.PriorityFunction;
4848
import org.apache.hadoop.hbase.ipc.RpcScheduler;
4949
import org.apache.hadoop.hbase.master.HMaster;
50+
import org.apache.hadoop.hbase.regionserver.HRegion;
5051
import org.apache.hadoop.hbase.regionserver.HRegionServer;
5152
import org.apache.hadoop.hbase.regionserver.RSRpcServices;
5253
import org.apache.hadoop.hbase.regionserver.SimpleRpcSchedulerFactory;
@@ -866,7 +867,8 @@ public void testEmptyMetaDaughterLocationDuringSplit() throws IOException {
866867
List<RegionInfo> regionInfos = Lists.newArrayList(parent);
867868
MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3);
868869

869-
MetaTableAccessor.splitRegion(connection, parent, -1L, splitA, splitB, serverName0, 3);
870+
MetaTableAccessor.splitRegion(connection, parent, -1L, splitA, splitB,
871+
serverName0, 3);
870872
Get get1 = new Get(splitA.getRegionName());
871873
Result resultA = meta.get(get1);
872874
Cell serverCellA = resultA.getColumnLatestCell(HConstants.CATALOG_FAMILY,
@@ -890,5 +892,28 @@ public void testEmptyMetaDaughterLocationDuringSplit() throws IOException {
890892
}
891893
}
892894
}
895+
896+
@Test
897+
public void testScanByRegionEncodedNameExistingRegion() throws Exception {
898+
final TableName tableName = TableName.valueOf("testScanByRegionEncodedNameExistingRegion");
899+
UTIL.createTable(tableName, "cf");
900+
final List<HRegion> regions = UTIL.getHBaseCluster().getRegions(tableName);
901+
final String encodedName = regions.get(0).getRegionInfo().getEncodedName();
902+
final Result result = MetaTableAccessor.scanByRegionEncodedName(UTIL.getConnection(),
903+
encodedName);
904+
assertNotNull(result);
905+
assertTrue(result.advance());
906+
final String resultingRowKey = CellUtil.getCellKeyAsString(result.current());
907+
assertTrue(resultingRowKey.contains(encodedName));
908+
UTIL.deleteTable(tableName);
909+
}
910+
911+
@Test
912+
public void testScanByRegionEncodedNameNonExistingRegion() throws Exception {
913+
final String encodedName = "nonexistingregion";
914+
final Result result = MetaTableAccessor.scanByRegionEncodedName(UTIL.getConnection(),
915+
encodedName);
916+
assertNull(result);
917+
}
893918
}
894919

hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestAssignmentManager.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
package org.apache.hadoop.hbase.master.assignment;
1919

2020
import static org.junit.Assert.assertEquals;
21+
import static org.junit.Assert.assertNull;
2122
import static org.junit.Assert.assertTrue;
2223

2324
import java.util.concurrent.Executors;
2425
import java.util.concurrent.Future;
2526
import org.apache.hadoop.hbase.HBaseClassTestRule;
2627
import org.apache.hadoop.hbase.HBaseTestingUtility;
28+
import org.apache.hadoop.hbase.MetaTableAccessor;
2729
import org.apache.hadoop.hbase.TableName;
2830
import org.apache.hadoop.hbase.client.RegionInfo;
2931
import org.apache.hadoop.hbase.client.RegionInfoBuilder;
@@ -285,4 +287,43 @@ public void testReopen() throws Exception {
285287
assertEquals(reopenFailedCount, reopenProcMetrics.getFailedCounter().getCount());
286288
assertCloseThenOpen();
287289
}
290+
291+
@Test
292+
public void testLoadRegionFromMetaAfterRegionManuallyAdded() throws Exception {
293+
try {
294+
this.util.startMiniCluster();
295+
final AssignmentManager am = this.util.getHBaseCluster().getMaster().getAssignmentManager();
296+
final TableName tableName = TableName.
297+
valueOf("testLoadRegionFromMetaAfterRegionManuallyAdded");
298+
this.util.createTable(tableName, "f");
299+
RegionInfo hri = createRegionInfo(tableName, 1);
300+
assertNull("RegionInfo was just instantiated by the test, but "
301+
+ "shouldn't be in AM regionStates yet.", am.getRegionStates().getRegionState(hri));
302+
MetaTableAccessor.addRegionToMeta(this.util.getConnection(), hri);
303+
assertNull("RegionInfo was manually added in META, but "
304+
+ "shouldn't be in AM regionStates yet.", am.getRegionStates().getRegionState(hri));
305+
hri = am.loadRegionFromMeta(hri.getEncodedName());
306+
assertEquals(hri.getEncodedName(),
307+
am.getRegionStates().getRegionState(hri).getRegion().getEncodedName());
308+
}finally {
309+
this.util.killMiniHBaseCluster();
310+
}
311+
}
312+
313+
@Test
314+
public void testLoadRegionFromMetaRegionNotInMeta() throws Exception {
315+
try {
316+
this.util.startMiniCluster();
317+
final AssignmentManager am = this.util.getHBaseCluster().getMaster().getAssignmentManager();
318+
final TableName tableName = TableName.valueOf("testLoadRegionFromMetaRegionNotInMeta");
319+
this.util.createTable(tableName, "f");
320+
final RegionInfo hri = createRegionInfo(tableName, 1);
321+
assertNull("RegionInfo was just instantiated by the test, but "
322+
+ "shouldn't be in AM regionStates yet.", am.getRegionStates().getRegionState(hri));
323+
assertNull("RegionInfo was never added in META, should had returned null.",
324+
am.loadRegionFromMeta(hri.getEncodedName()));
325+
}finally {
326+
this.util.killMiniHBaseCluster();
327+
}
328+
}
288329
}

0 commit comments

Comments
 (0)