Skip to content
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 @@ -64,8 +64,12 @@ public CompletableFuture<List<HRegionLocation>> getAllRegionLocations() {
}
CompletableFuture<List<HRegionLocation>> future = AsyncMetaTableAccessor
.getTableHRegionLocations(conn.getTable(TableName.META_TABLE_NAME), tableName);
addListener(future, (locs, error) -> locs
.forEach(loc -> conn.getLocator().getNonMetaRegionLocator().addLocationToCache(loc)));
addListener(future, (locs, error) -> locs.forEach(loc -> {
// the cache assumes that all locations have a serverName. only add if that's true
if (loc.getServerName() != null) {
conn.getLocator().getNonMetaRegionLocator().addLocationToCache(loc);
}
}));
return future;
}, getClass().getSimpleName() + ".getAllRegionLocations");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ public List<HRegionLocation> getAllRegionLocations() throws IOException {
for (HRegionLocation location : locations.getRegionLocations()) {
regions.add(location);
}
connection.cacheLocation(tableName, locations);
RegionLocations cleaned = locations.removeElementsWithNullLocation();
// above can return null if all locations had null location
if (cleaned != null) {
connection.cacheLocation(tableName, cleaned);
}
}
return regions;
}, HRegionLocator::getRegionNames, supplier);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;

import java.io.IOException;
Expand All @@ -41,6 +42,7 @@
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.MetaTableAccessor;
import org.apache.hadoop.hbase.NotServingRegionException;
import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.ServerName;
Expand All @@ -52,6 +54,7 @@
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
import org.junit.After;
import org.junit.AfterClass;
Expand All @@ -64,6 +67,7 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;

import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
import org.apache.hbase.thirdparty.com.google.common.io.Closeables;

@Category({ MediumTests.class, ClientTests.class })
Expand Down Expand Up @@ -476,4 +480,66 @@ public void testCacheLocationWhenGetAllLocations() throws Exception {
region.getStartKey()));
}
}

@Test
public void testDoNotCacheLocationWithNullServerNameWhenGetAllLocations() throws Exception {
createMultiRegionTable();
AsyncConnectionImpl conn = (AsyncConnectionImpl) ConnectionFactory
.createAsyncConnection(TEST_UTIL.getConfiguration()).get();
List<RegionInfo> regions = TEST_UTIL.getAdmin().getRegions(TABLE_NAME);
RegionInfo chosen = regions.get(0);

// re-populate region cache
AsyncTableRegionLocator regionLocator = conn.getRegionLocator(TABLE_NAME);
regionLocator.clearRegionLocationCache();
regionLocator.getAllRegionLocations().get();

// expect all to be non-null at first
int tries = 3;
checkRegionsWithRetries(conn, regions, null, tries);

// clear servername from region info
Put put = MetaTableAccessor.makePutFromRegionInfo(chosen, EnvironmentEdgeManager.currentTime());
MetaTableAccessor.addEmptyLocation(put, 0);
MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Lists.newArrayList(put));

// re-populate region cache again. check that we succeeded in nulling the servername
regionLocator.clearRegionLocationCache();
for (HRegionLocation loc : regionLocator.getAllRegionLocations().get()) {
if (loc.getRegion().equals(chosen)) {
assertNull(loc.getServerName());
}
}

// expect all but chosen to be non-null. chosen should be null because serverName was null
checkRegionsWithRetries(conn, regions, chosen, tries);
}

// caching of getAllRegionLocations is async. so we give it a couple tries
private void checkRegionsWithRetries(AsyncConnectionImpl conn, List<RegionInfo> regions,
RegionInfo chosen, int retries) throws InterruptedException {
while (true) {
try {
checkRegions(conn, regions, chosen);
break;
} catch (AssertionError e) {
if (retries-- <= 0) {
throw e;
}
Thread.sleep(500);
}
}
}

private void checkRegions(AsyncConnectionImpl conn, List<RegionInfo> regions, RegionInfo chosen) {
for (RegionInfo region : regions) {
RegionLocations fromCache = conn.getLocator().getNonMetaRegionLocator()
.getRegionLocationInCache(TABLE_NAME, region.getStartKey());
if (region.equals(chosen)) {
assertNull(fromCache);
} else {
assertNotNull(fromCache);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.hadoop.hbase.client;

import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

Expand All @@ -26,15 +27,23 @@
import java.util.List;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.MetaTableAccessor;
import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;

import org.apache.hbase.thirdparty.com.google.common.collect.Lists;

@Category({ MediumTests.class, ClientTests.class })
public class TestRegionLocationCaching {
Expand All @@ -50,6 +59,9 @@ public class TestRegionLocationCaching {
private static byte[] FAMILY = Bytes.toBytes("testFamily");
private static byte[] QUALIFIER = Bytes.toBytes("testQualifier");

@Rule
public final TestName name = new TestName();

@BeforeClass
public static void setUpBeforeClass() throws Exception {
TEST_UTIL.startMiniCluster(SLAVES);
Expand All @@ -62,6 +74,53 @@ public static void tearDownAfterClass() throws Exception {
TEST_UTIL.shutdownMiniCluster();
}

@Test
public void testDoNotCacheLocationWithNullServerNameWhenGetAllLocations() throws Exception {
TableName tableName = TableName.valueOf(name.getMethodName());
TEST_UTIL.createTable(tableName, new byte[][] { FAMILY });
TEST_UTIL.waitUntilAllRegionsAssigned(tableName);

ConnectionImplementation conn = (ConnectionImplementation) TEST_UTIL.getConnection();
List<RegionInfo> regions = TEST_UTIL.getAdmin().getRegions(tableName);
RegionInfo chosen = regions.get(0);

// re-populate region cache
RegionLocator regionLocator = TEST_UTIL.getConnection().getRegionLocator(tableName);
regionLocator.clearRegionLocationCache();
regionLocator.getAllRegionLocations();

// expect all to be non-null at first
checkRegions(tableName, conn, regions, null);

// clear servername from region info
Put put = MetaTableAccessor.makePutFromRegionInfo(chosen, EnvironmentEdgeManager.currentTime());
MetaTableAccessor.addEmptyLocation(put, 0);
MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Lists.newArrayList(put));

// re-populate region cache again. check that we succeeded in nulling the servername
regionLocator.clearRegionLocationCache();
for (HRegionLocation loc : regionLocator.getAllRegionLocations()) {
if (loc.getRegion().equals(chosen)) {
assertNull(loc.getServerName());
}
}

// expect all but chosen to be non-null. chosen should be null because serverName was null
checkRegions(tableName, conn, regions, chosen);
}

private void checkRegions(TableName tableName, ConnectionImplementation conn,
List<RegionInfo> regions, RegionInfo chosen) {
for (RegionInfo region : regions) {
RegionLocations fromCache = conn.getCachedLocation(tableName, region.getStartKey());
if (region.equals(chosen)) {
assertNull(fromCache);
} else {
assertNotNull(fromCache);
}
}
}

@Test
public void testCachingForHTableMultiplexerSinglePut() throws Exception {
HTableMultiplexer multiplexer =
Expand Down