001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import static java.util.stream.Collectors.toList; 021import static org.apache.hadoop.hbase.HConstants.EMPTY_END_ROW; 022import static org.apache.hadoop.hbase.HConstants.EMPTY_START_ROW; 023import static org.apache.hadoop.hbase.client.RegionReplicaTestHelper.testLocator; 024import static org.hamcrest.CoreMatchers.instanceOf; 025import static org.hamcrest.MatcherAssert.assertThat; 026import static org.junit.Assert.assertArrayEquals; 027import static org.junit.Assert.assertEquals; 028import static org.junit.Assert.assertNotNull; 029import static org.junit.Assert.assertNull; 030import static org.junit.Assert.assertSame; 031 032import java.io.IOException; 033import java.util.Arrays; 034import java.util.Collection; 035import java.util.List; 036import java.util.concurrent.CompletableFuture; 037import java.util.concurrent.ExecutionException; 038import java.util.concurrent.ThreadLocalRandom; 039import java.util.stream.IntStream; 040import org.apache.hadoop.conf.Configuration; 041import org.apache.hadoop.hbase.CatalogReplicaMode; 042import org.apache.hadoop.hbase.HBaseClassTestRule; 043import org.apache.hadoop.hbase.HBaseTestingUtil; 044import org.apache.hadoop.hbase.HRegionLocation; 045import org.apache.hadoop.hbase.MetaTableAccessor; 046import org.apache.hadoop.hbase.NotServingRegionException; 047import org.apache.hadoop.hbase.RegionLocations; 048import org.apache.hadoop.hbase.ServerName; 049import org.apache.hadoop.hbase.TableName; 050import org.apache.hadoop.hbase.TableNotFoundException; 051import org.apache.hadoop.hbase.Waiter.ExplainingPredicate; 052import org.apache.hadoop.hbase.client.RegionReplicaTestHelper.Locator; 053import org.apache.hadoop.hbase.security.User; 054import org.apache.hadoop.hbase.testclassification.ClientTests; 055import org.apache.hadoop.hbase.testclassification.MediumTests; 056import org.apache.hadoop.hbase.util.Bytes; 057import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 058import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil; 059import org.junit.After; 060import org.junit.AfterClass; 061import org.junit.Before; 062import org.junit.BeforeClass; 063import org.junit.ClassRule; 064import org.junit.Test; 065import org.junit.experimental.categories.Category; 066import org.junit.runner.RunWith; 067import org.junit.runners.Parameterized; 068import org.junit.runners.Parameterized.Parameter; 069 070import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 071import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 072 073@Category({ MediumTests.class, ClientTests.class }) 074@RunWith(Parameterized.class) 075public class TestAsyncNonMetaRegionLocator { 076 077 @ClassRule 078 public static final HBaseClassTestRule CLASS_RULE = 079 HBaseClassTestRule.forClass(TestAsyncNonMetaRegionLocator.class); 080 081 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 082 083 private static final TableName TABLE_NAME = TableName.valueOf("async"); 084 085 private static byte[] FAMILY = Bytes.toBytes("cf"); 086 private static final int NB_SERVERS = 4; 087 private static final int NUM_OF_META_REPLICA = NB_SERVERS - 1; 088 089 private static byte[][] SPLIT_KEYS; 090 091 private AsyncConnectionImpl conn; 092 private AsyncNonMetaRegionLocator locator; 093 094 @Parameter 095 public CatalogReplicaMode metaReplicaMode; 096 097 @BeforeClass 098 public static void setUp() throws Exception { 099 Configuration conf = TEST_UTIL.getConfiguration(); 100 // Enable hbase:meta replication. 101 conf.setBoolean(ServerRegionReplicaUtil.REGION_REPLICA_REPLICATION_CATALOG_CONF_KEY, true); 102 conf.setLong("replication.source.sleepforretries", 10); // 10 ms 103 104 TEST_UTIL.startMiniCluster(NB_SERVERS); 105 Admin admin = TEST_UTIL.getAdmin(); 106 admin.balancerSwitch(false, true); 107 108 // Enable hbase:meta replication. 109 HBaseTestingUtil.setReplicas(admin, TableName.META_TABLE_NAME, NUM_OF_META_REPLICA); 110 TEST_UTIL.waitFor(30000, 111 () -> TEST_UTIL.getMiniHBaseCluster().getRegions(TableName.META_TABLE_NAME).size() 112 >= NUM_OF_META_REPLICA); 113 114 SPLIT_KEYS = new byte[8][]; 115 for (int i = 111; i < 999; i += 111) { 116 SPLIT_KEYS[i / 111 - 1] = Bytes.toBytes(String.format("%03d", i)); 117 } 118 } 119 120 @AfterClass 121 public static void tearDown() throws Exception { 122 TEST_UTIL.shutdownMiniCluster(); 123 } 124 125 @Before 126 public void setUpBeforeTest() throws InterruptedException, ExecutionException, IOException { 127 Configuration c = new Configuration(TEST_UTIL.getConfiguration()); 128 // Enable meta replica LoadBalance mode for this connection. 129 c.set(RegionLocator.LOCATOR_META_REPLICAS_MODE, metaReplicaMode.toString()); 130 ConnectionRegistry registry = 131 ConnectionRegistryFactory.create(TEST_UTIL.getConfiguration(), User.getCurrent()); 132 conn = 133 new AsyncConnectionImpl(c, registry, registry.getClusterId().get(), null, User.getCurrent()); 134 locator = new AsyncNonMetaRegionLocator(conn); 135 } 136 137 @After 138 public void tearDownAfterTest() throws IOException { 139 Admin admin = TEST_UTIL.getAdmin(); 140 if (admin.tableExists(TABLE_NAME)) { 141 if (admin.isTableEnabled(TABLE_NAME)) { 142 admin.disableTable(TABLE_NAME); 143 } 144 admin.deleteTable(TABLE_NAME); 145 } 146 Closeables.close(conn, true); 147 } 148 149 @Parameterized.Parameters 150 public static Collection<Object[]> paramAbstractTestRegionLocatoreters() { 151 return Arrays 152 .asList(new Object[][] { { CatalogReplicaMode.NONE }, { CatalogReplicaMode.LOAD_BALANCE } }); 153 } 154 155 private void createSingleRegionTable() throws IOException, InterruptedException { 156 TEST_UTIL.createTable(TABLE_NAME, FAMILY); 157 TEST_UTIL.waitTableAvailable(TABLE_NAME); 158 } 159 160 private CompletableFuture<HRegionLocation> getDefaultRegionLocation(TableName tableName, 161 byte[] row, RegionLocateType locateType, boolean reload) { 162 return locator 163 .getRegionLocations(tableName, row, RegionReplicaUtil.DEFAULT_REPLICA_ID, locateType, reload) 164 .thenApply(RegionLocations::getDefaultRegionLocation); 165 } 166 167 @Test 168 public void testNoTable() throws InterruptedException { 169 for (RegionLocateType locateType : RegionLocateType.values()) { 170 try { 171 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType, false).get(); 172 } catch (ExecutionException e) { 173 assertThat(e.getCause(), instanceOf(TableNotFoundException.class)); 174 } 175 } 176 } 177 178 @Test 179 public void testDisableTable() throws IOException, InterruptedException { 180 createSingleRegionTable(); 181 TEST_UTIL.getAdmin().disableTable(TABLE_NAME); 182 for (RegionLocateType locateType : RegionLocateType.values()) { 183 try { 184 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType, false).get(); 185 } catch (ExecutionException e) { 186 assertThat(e.getCause(), instanceOf(TableNotFoundException.class)); 187 } 188 } 189 } 190 191 private void assertLocEquals(byte[] startKey, byte[] endKey, ServerName serverName, 192 HRegionLocation loc) { 193 RegionInfo info = loc.getRegion(); 194 assertEquals(TABLE_NAME, info.getTable()); 195 assertArrayEquals(startKey, info.getStartKey()); 196 assertArrayEquals(endKey, info.getEndKey()); 197 assertEquals(serverName, loc.getServerName()); 198 } 199 200 @Test 201 public void testSingleRegionTable() throws IOException, InterruptedException, ExecutionException { 202 createSingleRegionTable(); 203 ServerName serverName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName(); 204 for (RegionLocateType locateType : RegionLocateType.values()) { 205 assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName, 206 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType, false).get()); 207 } 208 byte[] key = new byte[ThreadLocalRandom.current().nextInt(128)]; 209 Bytes.random(key); 210 for (RegionLocateType locateType : RegionLocateType.values()) { 211 assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName, 212 getDefaultRegionLocation(TABLE_NAME, key, locateType, false).get()); 213 } 214 } 215 216 private void createMultiRegionTable() throws IOException, InterruptedException { 217 TEST_UTIL.createTable(TABLE_NAME, FAMILY, SPLIT_KEYS); 218 TEST_UTIL.waitTableAvailable(TABLE_NAME); 219 } 220 221 private static byte[][] getStartKeys() { 222 byte[][] startKeys = new byte[SPLIT_KEYS.length + 1][]; 223 startKeys[0] = EMPTY_START_ROW; 224 System.arraycopy(SPLIT_KEYS, 0, startKeys, 1, SPLIT_KEYS.length); 225 return startKeys; 226 } 227 228 private static byte[][] getEndKeys() { 229 byte[][] endKeys = Arrays.copyOf(SPLIT_KEYS, SPLIT_KEYS.length + 1); 230 endKeys[endKeys.length - 1] = EMPTY_START_ROW; 231 return endKeys; 232 } 233 234 private ServerName[] getLocations(byte[][] startKeys) { 235 ServerName[] serverNames = new ServerName[startKeys.length]; 236 TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream().map(t -> t.getRegionServer()) 237 .forEach(rs -> { 238 rs.getRegions(TABLE_NAME).forEach(r -> { 239 serverNames[Arrays.binarySearch(startKeys, r.getRegionInfo().getStartKey(), 240 Bytes::compareTo)] = rs.getServerName(); 241 }); 242 }); 243 return serverNames; 244 } 245 246 @Test 247 public void testMultiRegionTable() throws IOException, InterruptedException { 248 createMultiRegionTable(); 249 byte[][] startKeys = getStartKeys(); 250 ServerName[] serverNames = getLocations(startKeys); 251 IntStream.range(0, 2).forEach(n -> IntStream.range(0, startKeys.length).forEach(i -> { 252 try { 253 assertLocEquals(startKeys[i], i == startKeys.length - 1 ? EMPTY_END_ROW : startKeys[i + 1], 254 serverNames[i], 255 getDefaultRegionLocation(TABLE_NAME, startKeys[i], RegionLocateType.CURRENT, false) 256 .get()); 257 } catch (InterruptedException | ExecutionException e) { 258 throw new RuntimeException(e); 259 } 260 })); 261 262 locator.clearCache(TABLE_NAME); 263 IntStream.range(0, 2).forEach(n -> IntStream.range(0, startKeys.length).forEach(i -> { 264 try { 265 assertLocEquals(startKeys[i], i == startKeys.length - 1 ? EMPTY_END_ROW : startKeys[i + 1], 266 serverNames[i], 267 getDefaultRegionLocation(TABLE_NAME, startKeys[i], RegionLocateType.AFTER, false).get()); 268 } catch (InterruptedException | ExecutionException e) { 269 throw new RuntimeException(e); 270 } 271 })); 272 273 locator.clearCache(TABLE_NAME); 274 byte[][] endKeys = getEndKeys(); 275 IntStream.range(0, 2).forEach( 276 n -> IntStream.range(0, endKeys.length).map(i -> endKeys.length - 1 - i).forEach(i -> { 277 try { 278 assertLocEquals(i == 0 ? EMPTY_START_ROW : endKeys[i - 1], endKeys[i], serverNames[i], 279 getDefaultRegionLocation(TABLE_NAME, endKeys[i], RegionLocateType.BEFORE, false).get()); 280 } catch (InterruptedException | ExecutionException e) { 281 throw new RuntimeException(e); 282 } 283 })); 284 } 285 286 @Test 287 public void testRegionMove() throws IOException, InterruptedException, ExecutionException { 288 createSingleRegionTable(); 289 ServerName serverName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName(); 290 HRegionLocation loc = 291 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT, false).get(); 292 assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName, loc); 293 ServerName newServerName = TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream() 294 .map(t -> t.getRegionServer().getServerName()).filter(sn -> !sn.equals(serverName)).findAny() 295 .get(); 296 297 TEST_UTIL.getAdmin().move(Bytes.toBytes(loc.getRegion().getEncodedName()), newServerName); 298 while ( 299 !TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName().equals(newServerName) 300 ) { 301 Thread.sleep(100); 302 } 303 // Should be same as it is in cache 304 assertSame(loc, 305 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT, false).get()); 306 locator.updateCachedLocationOnError(loc, null); 307 // null error will not trigger a cache cleanup 308 assertSame(loc, 309 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT, false).get()); 310 locator.updateCachedLocationOnError(loc, new NotServingRegionException()); 311 assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, newServerName, 312 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT, false).get()); 313 } 314 315 // usually locate after will return the same result, so we add a test to make it return different 316 // result. 317 @Test 318 public void testLocateAfter() throws IOException, InterruptedException, ExecutionException { 319 byte[] row = Bytes.toBytes("1"); 320 byte[] splitKey = Arrays.copyOf(row, 2); 321 TEST_UTIL.createTable(TABLE_NAME, FAMILY, new byte[][] { splitKey }); 322 TEST_UTIL.waitTableAvailable(TABLE_NAME); 323 HRegionLocation currentLoc = 324 getDefaultRegionLocation(TABLE_NAME, row, RegionLocateType.CURRENT, false).get(); 325 ServerName currentServerName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName(); 326 assertLocEquals(EMPTY_START_ROW, splitKey, currentServerName, currentLoc); 327 328 HRegionLocation afterLoc = 329 getDefaultRegionLocation(TABLE_NAME, row, RegionLocateType.AFTER, false).get(); 330 ServerName afterServerName = 331 TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream().map(t -> t.getRegionServer()) 332 .filter(rs -> rs.getRegions(TABLE_NAME).stream() 333 .anyMatch(r -> Bytes.equals(splitKey, r.getRegionInfo().getStartKey()))) 334 .findAny().get().getServerName(); 335 assertLocEquals(splitKey, EMPTY_END_ROW, afterServerName, afterLoc); 336 337 assertSame(afterLoc, 338 getDefaultRegionLocation(TABLE_NAME, row, RegionLocateType.AFTER, false).get()); 339 } 340 341 // For HBASE-17402 342 @Test 343 public void testConcurrentLocate() throws IOException, InterruptedException, ExecutionException { 344 createMultiRegionTable(); 345 byte[][] startKeys = getStartKeys(); 346 byte[][] endKeys = getEndKeys(); 347 ServerName[] serverNames = getLocations(startKeys); 348 for (int i = 0; i < 100; i++) { 349 locator.clearCache(TABLE_NAME); 350 List<CompletableFuture<HRegionLocation>> futures = 351 IntStream.range(0, 1000).mapToObj(n -> String.format("%03d", n)).map(s -> Bytes.toBytes(s)) 352 .map(r -> getDefaultRegionLocation(TABLE_NAME, r, RegionLocateType.CURRENT, false)) 353 .collect(toList()); 354 for (int j = 0; j < 1000; j++) { 355 int index = Math.min(8, j / 111); 356 assertLocEquals(startKeys[index], endKeys[index], serverNames[index], futures.get(j).get()); 357 } 358 } 359 } 360 361 @Test 362 public void testReload() throws Exception { 363 createSingleRegionTable(); 364 ServerName serverName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName(); 365 for (RegionLocateType locateType : RegionLocateType.values()) { 366 assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName, 367 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType, false).get()); 368 } 369 ServerName newServerName = TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream() 370 .map(t -> t.getRegionServer().getServerName()).filter(sn -> !sn.equals(serverName)).findAny() 371 .get(); 372 Admin admin = TEST_UTIL.getAdmin(); 373 RegionInfo region = admin.getRegions(TABLE_NAME).stream().findAny().get(); 374 admin.move(region.getEncodedNameAsBytes(), newServerName); 375 TEST_UTIL.waitFor(30000, new ExplainingPredicate<Exception>() { 376 377 @Override 378 public boolean evaluate() throws Exception { 379 ServerName newServerName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName(); 380 return newServerName != null && !newServerName.equals(serverName); 381 } 382 383 @Override 384 public String explainFailure() throws Exception { 385 return region.getRegionNameAsString() + " is still on " + serverName; 386 } 387 388 }); 389 // The cached location will not change 390 for (RegionLocateType locateType : RegionLocateType.values()) { 391 assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName, 392 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType, false).get()); 393 } 394 // should get the new location when reload = true 395 // when meta replica LoadBalance mode is enabled, it may delay a bit. 396 TEST_UTIL.waitFor(3000, new ExplainingPredicate<Exception>() { 397 @Override 398 public boolean evaluate() throws Exception { 399 HRegionLocation loc = 400 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT, true) 401 .get(); 402 return newServerName.equals(loc.getServerName()); 403 } 404 405 @Override 406 public String explainFailure() throws Exception { 407 return "New location does not show up in meta (replica) region"; 408 } 409 }); 410 411 // the cached location should be replaced 412 for (RegionLocateType locateType : RegionLocateType.values()) { 413 assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, newServerName, 414 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType, false).get()); 415 } 416 } 417 418 // Testcase for HBASE-20822 419 @Test 420 public void testLocateBeforeLastRegion() 421 throws IOException, InterruptedException, ExecutionException { 422 createMultiRegionTable(); 423 getDefaultRegionLocation(TABLE_NAME, SPLIT_KEYS[0], RegionLocateType.CURRENT, false).join(); 424 HRegionLocation loc = 425 getDefaultRegionLocation(TABLE_NAME, EMPTY_END_ROW, RegionLocateType.BEFORE, false).get(); 426 // should locate to the last region 427 assertArrayEquals(loc.getRegion().getEndKey(), EMPTY_END_ROW); 428 } 429 430 @Test 431 public void testRegionReplicas() throws Exception { 432 TEST_UTIL.getAdmin().createTable(TableDescriptorBuilder.newBuilder(TABLE_NAME) 433 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).setRegionReplication(3).build()); 434 TEST_UTIL.waitUntilAllRegionsAssigned(TABLE_NAME); 435 testLocator(TEST_UTIL, TABLE_NAME, new Locator() { 436 437 @Override 438 public void updateCachedLocationOnError(HRegionLocation loc, Throwable error) 439 throws Exception { 440 locator.updateCachedLocationOnError(loc, error); 441 } 442 443 @Override 444 public RegionLocations getRegionLocations(TableName tableName, int replicaId, boolean reload) 445 throws Exception { 446 return locator.getRegionLocations(tableName, EMPTY_START_ROW, replicaId, 447 RegionLocateType.CURRENT, reload).get(); 448 } 449 }); 450 } 451 452 // Testcase for HBASE-21961 453 @Test 454 public void testLocateBeforeInOnlyRegion() throws IOException, InterruptedException { 455 createSingleRegionTable(); 456 HRegionLocation loc = 457 getDefaultRegionLocation(TABLE_NAME, Bytes.toBytes(1), RegionLocateType.BEFORE, false).join(); 458 // should locate to the only region 459 assertArrayEquals(loc.getRegion().getStartKey(), EMPTY_START_ROW); 460 assertArrayEquals(loc.getRegion().getEndKey(), EMPTY_END_ROW); 461 } 462 463 @Test 464 public void testConcurrentUpdateCachedLocationOnError() throws Exception { 465 createSingleRegionTable(); 466 HRegionLocation loc = 467 getDefaultRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT, false).get(); 468 IntStream.range(0, 100).parallel() 469 .forEach(i -> locator.updateCachedLocationOnError(loc, new NotServingRegionException())); 470 } 471 472 @Test 473 public void testCacheLocationWhenGetAllLocations() throws Exception { 474 createMultiRegionTable(); 475 AsyncConnectionImpl conn = (AsyncConnectionImpl) ConnectionFactory 476 .createAsyncConnection(TEST_UTIL.getConfiguration()).get(); 477 conn.getRegionLocator(TABLE_NAME).getAllRegionLocations().get(); 478 List<RegionInfo> regions = TEST_UTIL.getAdmin().getRegions(TABLE_NAME); 479 for (RegionInfo region : regions) { 480 assertNotNull(conn.getLocator().getRegionLocationInCache(TABLE_NAME, region.getStartKey())); 481 } 482 } 483 484 @Test 485 public void testDoNotCacheLocationWithNullServerNameWhenGetAllLocations() throws Exception { 486 createMultiRegionTable(); 487 AsyncConnectionImpl conn = (AsyncConnectionImpl) ConnectionFactory 488 .createAsyncConnection(TEST_UTIL.getConfiguration()).get(); 489 List<RegionInfo> regions = TEST_UTIL.getAdmin().getRegions(TABLE_NAME); 490 RegionInfo chosen = regions.get(0); 491 492 // re-populate region cache 493 AsyncTableRegionLocator regionLocator = conn.getRegionLocator(TABLE_NAME); 494 regionLocator.clearRegionLocationCache(); 495 regionLocator.getAllRegionLocations().get(); 496 497 int tries = 3; 498 // expect all to be non-null at first 499 checkRegionsWithRetries(conn, regions, null, tries); 500 501 // clear servername from region info 502 Put put = MetaTableAccessor.makePutFromRegionInfo(chosen, EnvironmentEdgeManager.currentTime()); 503 MetaTableAccessor.addEmptyLocation(put, 0); 504 MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Lists.newArrayList(put)); 505 506 // re-populate region cache again. check that we succeeded in nulling the servername 507 regionLocator.clearRegionLocationCache(); 508 for (HRegionLocation loc : regionLocator.getAllRegionLocations().get()) { 509 if (loc.getRegion().equals(chosen)) { 510 assertNull(loc.getServerName()); 511 } 512 } 513 514 // expect all but chosen to be non-null. chosen should be null because serverName was null 515 checkRegionsWithRetries(conn, regions, chosen, tries); 516 } 517 518 // caching of getAllRegionLocations is async. so we give it a couple tries 519 private void checkRegionsWithRetries(AsyncConnectionImpl conn, List<RegionInfo> regions, 520 RegionInfo chosen, int retries) throws InterruptedException { 521 while (true) { 522 try { 523 checkRegions(conn, regions, chosen); 524 break; 525 } catch (AssertionError e) { 526 if (retries-- <= 0) { 527 throw e; 528 } 529 Thread.sleep(500); 530 } 531 } 532 } 533 534 private void checkRegions(AsyncConnectionImpl conn, List<RegionInfo> regions, RegionInfo chosen) { 535 for (RegionInfo region : regions) { 536 RegionLocations fromCache = 537 conn.getLocator().getRegionLocationInCache(TABLE_NAME, region.getStartKey()); 538 if (region.equals(chosen)) { 539 assertNull(fromCache); 540 } else { 541 assertNotNull(fromCache); 542 } 543 } 544 } 545}