HBASE-17402 TestAsyncTableScan sometimes hangs

This commit is contained in:
zhangduo 2017-02-07 09:31:38 +08:00
parent 9ec0ec4922
commit af9d359b8e
2 changed files with 60 additions and 32 deletions

View File

@ -53,7 +53,6 @@ import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException; import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.client.Scan.ReadType;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
/** /**
@ -140,8 +139,8 @@ class AsyncNonMetaRegionLocator {
return; return;
} }
tableCache.cache.computeIfPresent(loc.getRegionInfo().getStartKey(), (k, oldLoc) -> { tableCache.cache.computeIfPresent(loc.getRegionInfo().getStartKey(), (k, oldLoc) -> {
if (oldLoc.getSeqNum() > loc.getSeqNum() if (oldLoc.getSeqNum() > loc.getSeqNum() ||
|| !oldLoc.getServerName().equals(loc.getServerName())) { !oldLoc.getServerName().equals(loc.getServerName())) {
return oldLoc; return oldLoc;
} }
return null; return null;
@ -158,11 +157,11 @@ class AsyncNonMetaRegionLocator {
if (oldLoc == null) { if (oldLoc == null) {
return true; return true;
} }
if (oldLoc.getSeqNum() > loc.getSeqNum() if (oldLoc.getSeqNum() > loc.getSeqNum() ||
|| oldLoc.getServerName().equals(loc.getServerName())) { oldLoc.getServerName().equals(loc.getServerName())) {
if (LOG.isTraceEnabled()) { if (LOG.isTraceEnabled()) {
LOG.trace("Will not add " + loc + " to cache because the old value " + oldLoc LOG.trace("Will not add " + loc + " to cache because the old value " + oldLoc +
+ " is newer than us or has the same server name"); " is newer than us or has the same server name");
} }
return false; return false;
} }
@ -171,9 +170,9 @@ class AsyncNonMetaRegionLocator {
return loc; return loc;
} }
if (LOG.isTraceEnabled()) { if (LOG.isTraceEnabled()) {
LOG.trace("Will not add " + loc + " to cache because the old value " + oldValue LOG.trace("Will not add " + loc + " to cache because the old value " + oldValue +
+ " is newer than us or has the same server name." " is newer than us or has the same server name." +
+ " Maybe it is updated before we replace it"); " Maybe it is updated before we replace it");
} }
return oldValue; return oldValue;
}); });
@ -217,8 +216,8 @@ class AsyncNonMetaRegionLocator {
Throwable error) { Throwable error) {
if (error != null) { if (error != null) {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Failed to locate region in '" + tableName + "', row='" LOG.debug("Failed to locate region in '" + tableName + "', row='" +
+ Bytes.toStringBinary(req.row) + "', locateType=" + req.locateType, Bytes.toStringBinary(req.row) + "', locateType=" + req.locateType,
error); error);
} }
} }
@ -250,14 +249,15 @@ class AsyncNonMetaRegionLocator {
} }
} }
} }
if (!tableCache.allRequests.isEmpty() if (!tableCache.allRequests.isEmpty() &&
&& tableCache.hasQuota(maxConcurrentLocateRequestPerTable)) { tableCache.hasQuota(maxConcurrentLocateRequestPerTable)) {
LocateRequest[] candidates = tableCache.allRequests.keySet().stream() LocateRequest[] candidates = tableCache.allRequests.keySet().stream()
.filter(r -> !tableCache.isPending(r)).toArray(LocateRequest[]::new); .filter(r -> !tableCache.isPending(r)).toArray(LocateRequest[]::new);
if (candidates.length > 0) { if (candidates.length > 0) {
// TODO: use a better algorithm to send a request which is more likely to fetch a new // TODO: use a better algorithm to send a request which is more likely to fetch a new
// location. // location.
toSend = candidates[ThreadLocalRandom.current().nextInt(candidates.length)]; toSend = candidates[ThreadLocalRandom.current().nextInt(candidates.length)];
tableCache.send(toSend);
} }
} }
} }
@ -278,8 +278,8 @@ class AsyncNonMetaRegionLocator {
} }
RegionLocations locs = MetaTableAccessor.getRegionLocations(results.get(0)); RegionLocations locs = MetaTableAccessor.getRegionLocations(results.get(0));
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("The fetched location of '" + tableName + "', row='" + Bytes.toStringBinary(req.row) LOG.debug("The fetched location of '" + tableName + "', row='" +
+ "', locateType=" + req.locateType + " is " + locs); Bytes.toStringBinary(req.row) + "', locateType=" + req.locateType + " is " + locs);
} }
if (locs == null || locs.getDefaultRegionLocation() == null) { if (locs == null || locs.getDefaultRegionLocation() == null) {
complete(tableName, req, null, complete(tableName, req, null,
@ -303,13 +303,13 @@ class AsyncNonMetaRegionLocator {
if (info.isSplit()) { if (info.isSplit()) {
complete(tableName, req, null, complete(tableName, req, null,
new RegionOfflineException( new RegionOfflineException(
"the only available region for the required row is a split parent," "the only available region for the required row is a split parent," +
+ " the daughters should be online soon: '" + info.getRegionNameAsString() + "'")); " the daughters should be online soon: '" + info.getRegionNameAsString() + "'"));
return; return;
} }
if (info.isOffline()) { if (info.isOffline()) {
complete(tableName, req, null, new RegionOfflineException("the region is offline, could" complete(tableName, req, null, new RegionOfflineException("the region is offline, could" +
+ " be caused by a disable table call: '" + info.getRegionNameAsString() + "'")); " be caused by a disable table call: '" + info.getRegionNameAsString() + "'"));
return; return;
} }
if (loc.getServerName() == null) { if (loc.getServerName() == null) {
@ -331,8 +331,8 @@ class AsyncNonMetaRegionLocator {
byte[] endKey = loc.getRegionInfo().getEndKey(); byte[] endKey = loc.getRegionInfo().getEndKey();
if (isEmptyStopRow(endKey) || Bytes.compareTo(row, endKey) < 0) { if (isEmptyStopRow(endKey) || Bytes.compareTo(row, endKey) < 0) {
if (LOG.isTraceEnabled()) { if (LOG.isTraceEnabled()) {
LOG.trace("Found " + loc + " in cache for '" + tableName + "', row='" LOG.trace("Found " + loc + " in cache for '" + tableName + "', row='" +
+ Bytes.toStringBinary(row) + "', locateType=" + RegionLocateType.CURRENT); Bytes.toStringBinary(row) + "', locateType=" + RegionLocateType.CURRENT);
} }
return loc; return loc;
} else { } else {
@ -348,11 +348,11 @@ class AsyncNonMetaRegionLocator {
return null; return null;
} }
HRegionLocation loc = entry.getValue(); HRegionLocation loc = entry.getValue();
if (isEmptyStopRow(loc.getRegionInfo().getEndKey()) if (isEmptyStopRow(loc.getRegionInfo().getEndKey()) ||
|| Bytes.compareTo(loc.getRegionInfo().getEndKey(), row) >= 0) { Bytes.compareTo(loc.getRegionInfo().getEndKey(), row) >= 0) {
if (LOG.isTraceEnabled()) { if (LOG.isTraceEnabled()) {
LOG.trace("Found " + loc + " in cache for '" + tableName + "', row='" LOG.trace("Found " + loc + " in cache for '" + tableName + "', row='" +
+ Bytes.toStringBinary(row) + "', locateType=" + RegionLocateType.BEFORE); Bytes.toStringBinary(row) + "', locateType=" + RegionLocateType.BEFORE);
} }
return loc; return loc;
} else { } else {
@ -362,8 +362,8 @@ class AsyncNonMetaRegionLocator {
private void locateInMeta(TableName tableName, LocateRequest req) { private void locateInMeta(TableName tableName, LocateRequest req) {
if (LOG.isTraceEnabled()) { if (LOG.isTraceEnabled()) {
LOG.trace("Try locate '" + tableName + "', row='" + Bytes.toStringBinary(req.row) LOG.trace("Try locate '" + tableName + "', row='" + Bytes.toStringBinary(req.row) +
+ "', locateType=" + req.locateType + " in meta"); "', locateType=" + req.locateType + " in meta");
} }
byte[] metaKey; byte[] metaKey;
if (req.locateType.equals(RegionLocateType.BEFORE)) { if (req.locateType.equals(RegionLocateType.BEFORE)) {

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.hadoop.hbase.client; package org.apache.hadoop.hbase.client;
import static java.util.stream.Collectors.toList;
import static org.apache.hadoop.hbase.HConstants.EMPTY_END_ROW; import static org.apache.hadoop.hbase.HConstants.EMPTY_END_ROW;
import static org.apache.hadoop.hbase.HConstants.EMPTY_START_ROW; import static org.apache.hadoop.hbase.HConstants.EMPTY_START_ROW;
import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.instanceOf;
@ -27,6 +28,8 @@ import static org.junit.Assert.assertThat;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -166,10 +169,7 @@ public class TestAsyncNonMetaRegionLocator {
return endKeys; return endKeys;
} }
@Test private ServerName[] getLocations(byte[][] startKeys) {
public void testMultiRegionTable() throws IOException, InterruptedException {
createMultiRegionTable();
byte[][] startKeys = getStartKeys();
ServerName[] serverNames = new ServerName[startKeys.length]; ServerName[] serverNames = new ServerName[startKeys.length];
TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream().map(t -> t.getRegionServer()) TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream().map(t -> t.getRegionServer())
.forEach(rs -> { .forEach(rs -> {
@ -178,6 +178,14 @@ public class TestAsyncNonMetaRegionLocator {
Bytes::compareTo)] = rs.getServerName(); Bytes::compareTo)] = rs.getServerName();
}); });
}); });
return serverNames;
}
@Test
public void testMultiRegionTable() throws IOException, InterruptedException {
createMultiRegionTable();
byte[][] startKeys = getStartKeys();
ServerName[] serverNames = getLocations(startKeys);
IntStream.range(0, 2).forEach(n -> IntStream.range(0, startKeys.length).forEach(i -> { IntStream.range(0, 2).forEach(n -> IntStream.range(0, startKeys.length).forEach(i -> {
try { try {
assertLocEquals(startKeys[i], i == startKeys.length - 1 ? EMPTY_END_ROW : startKeys[i + 1], assertLocEquals(startKeys[i], i == startKeys.length - 1 ? EMPTY_END_ROW : startKeys[i + 1],
@ -264,4 +272,24 @@ public class TestAsyncNonMetaRegionLocator {
assertSame(afterLoc, LOCATOR.getRegionLocation(TABLE_NAME, row, RegionLocateType.AFTER).get()); assertSame(afterLoc, LOCATOR.getRegionLocation(TABLE_NAME, row, RegionLocateType.AFTER).get());
} }
// For HBASE-17402
@Test
public void testConcurrentLocate() throws IOException, InterruptedException, ExecutionException {
createMultiRegionTable();
byte[][] startKeys = getStartKeys();
byte[][] endKeys = getEndKeys();
ServerName[] serverNames = getLocations(startKeys);
for (int i = 0; i < 100; i++) {
LOCATOR.clearCache(TABLE_NAME);
List<CompletableFuture<HRegionLocation>> futures = IntStream.range(0, 1000)
.mapToObj(n -> String.format("%03d", n)).map(s -> Bytes.toBytes(s))
.map(r -> LOCATOR.getRegionLocation(TABLE_NAME, r, RegionLocateType.CURRENT))
.collect(toList());
for (int j = 0; j < 1000; j++) {
int index = Math.min(8, j / 111);
assertLocEquals(startKeys[index], endKeys[index], serverNames[index], futures.get(j).get());
}
}
}
} }