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.replication.regionserver; 019 020import static org.apache.hadoop.hbase.client.RegionLocator.LOCATOR_META_REPLICAS_MODE; 021import static org.junit.Assert.assertArrayEquals; 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertFalse; 024import static org.junit.Assert.assertNotNull; 025import static org.junit.Assert.assertTrue; 026 027import java.io.IOException; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.List; 031import java.util.Objects; 032import java.util.concurrent.TimeUnit; 033import org.apache.commons.lang3.mutable.MutableObject; 034import org.apache.hadoop.conf.Configuration; 035import org.apache.hadoop.hbase.Cell; 036import org.apache.hadoop.hbase.CellScanner; 037import org.apache.hadoop.hbase.CellUtil; 038import org.apache.hadoop.hbase.HBaseClassTestRule; 039import org.apache.hadoop.hbase.HBaseTestingUtility; 040import org.apache.hadoop.hbase.HConstants; 041import org.apache.hadoop.hbase.HRegionLocation; 042import org.apache.hadoop.hbase.MetaTableAccessor; 043import org.apache.hadoop.hbase.MiniHBaseCluster; 044import org.apache.hadoop.hbase.TableName; 045import org.apache.hadoop.hbase.Waiter; 046import org.apache.hadoop.hbase.client.Connection; 047import org.apache.hadoop.hbase.client.ConnectionFactory; 048import org.apache.hadoop.hbase.client.Get; 049import org.apache.hadoop.hbase.client.RegionInfo; 050import org.apache.hadoop.hbase.client.RegionLocator; 051import org.apache.hadoop.hbase.client.Result; 052import org.apache.hadoop.hbase.client.Scan; 053import org.apache.hadoop.hbase.client.Table; 054import org.apache.hadoop.hbase.regionserver.HRegion; 055import org.apache.hadoop.hbase.regionserver.HRegionServer; 056import org.apache.hadoop.hbase.regionserver.Region; 057import org.apache.hadoop.hbase.regionserver.RegionScanner; 058import org.apache.hadoop.hbase.replication.ReplicationPeerImpl; 059import org.apache.hadoop.hbase.testclassification.LargeTests; 060import org.apache.hadoop.hbase.util.Bytes; 061import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil; 062import org.junit.After; 063import org.junit.Before; 064import org.junit.ClassRule; 065import org.junit.Rule; 066import org.junit.Test; 067import org.junit.experimental.categories.Category; 068import org.junit.rules.TestName; 069import org.slf4j.Logger; 070import org.slf4j.LoggerFactory; 071 072/** 073 * Tests RegionReplicaReplicationEndpoint class for hbase:meta by setting up region replicas and 074 * verifying async wal replication replays the edits to the secondary region in various scenarios. 075 * @see TestRegionReplicaReplicationEndpoint 076 */ 077@Category({ LargeTests.class }) 078public class TestMetaRegionReplicaReplicationEndpoint { 079 @ClassRule 080 public static final HBaseClassTestRule CLASS_RULE = 081 HBaseClassTestRule.forClass(TestMetaRegionReplicaReplicationEndpoint.class); 082 private static final Logger LOG = 083 LoggerFactory.getLogger(TestMetaRegionReplicaReplicationEndpoint.class); 084 private static final int NB_SERVERS = 4; 085 private final HBaseTestingUtility HTU = new HBaseTestingUtility(); 086 private int numOfMetaReplica = NB_SERVERS - 1; 087 private static byte[] VALUE = Bytes.toBytes("value"); 088 089 @Rule 090 public TestName name = new TestName(); 091 092 @Before 093 public void before() throws Exception { 094 Configuration conf = HTU.getConfiguration(); 095 conf.setFloat("hbase.regionserver.logroll.multiplier", 0.0003f); 096 conf.setInt("replication.source.size.capacity", 10240); 097 conf.setLong("replication.source.sleepforretries", 100); 098 conf.setInt("hbase.regionserver.maxlogs", 10); 099 conf.setLong("hbase.master.logcleaner.ttl", 10); 100 conf.setInt("zookeeper.recovery.retry", 1); 101 conf.setInt("zookeeper.recovery.retry.intervalmill", 10); 102 conf.setLong(HConstants.THREAD_WAKE_FREQUENCY, 100); 103 conf.setInt("replication.stats.thread.period.seconds", 5); 104 conf.setBoolean("hbase.tests.use.shortcircuit.reads", false); 105 conf.setInt(HConstants.HBASE_CLIENT_SERVERSIDE_RETRIES_MULTIPLIER, 1); 106 // Enable hbase:meta replication. 107 conf.setBoolean(ServerRegionReplicaUtil.REGION_REPLICA_REPLICATION_CATALOG_CONF_KEY, true); 108 // Set hbase:meta replicas to be 3. 109 // conf.setInt(HConstants.META_REPLICAS_NUM, numOfMetaReplica); 110 HTU.startMiniCluster(NB_SERVERS); 111 // Enable hbase:meta replication. 112 HBaseTestingUtility.setReplicas(HTU.getAdmin(), TableName.META_TABLE_NAME, numOfMetaReplica); 113 114 HTU.waitFor(30000, () -> HTU.getMiniHBaseCluster().getRegions(TableName.META_TABLE_NAME).size() 115 >= numOfMetaReplica); 116 } 117 118 @After 119 public void after() throws Exception { 120 HTU.shutdownMiniCluster(); 121 } 122 123 /** 124 * Assert that the ReplicationSource for hbase:meta gets created when hbase:meta is opened. 125 */ 126 @Test 127 public void testHBaseMetaReplicationSourceCreatedOnOpen() throws Exception { 128 MiniHBaseCluster cluster = HTU.getMiniHBaseCluster(); 129 HRegionServer hrs = cluster.getRegionServer(cluster.getServerHoldingMeta()); 130 // Replicate a row to prove all working. 131 testHBaseMetaReplicatesOneRow(0); 132 assertTrue(isMetaRegionReplicaReplicationSource(hrs)); 133 // Now move the hbase:meta and make sure the ReplicationSource is in both places. 134 HRegionServer hrsOther = null; 135 for (int i = 0; i < cluster.getNumLiveRegionServers(); i++) { 136 hrsOther = cluster.getRegionServer(i); 137 if (hrsOther.getServerName().equals(hrs.getServerName())) { 138 hrsOther = null; 139 continue; 140 } 141 break; 142 } 143 assertNotNull(hrsOther); 144 assertFalse(isMetaRegionReplicaReplicationSource(hrsOther)); 145 Region meta = null; 146 for (Region region : hrs.getOnlineRegionsLocalContext()) { 147 if (region.getRegionInfo().isMetaRegion()) { 148 meta = region; 149 break; 150 } 151 } 152 assertNotNull(meta); 153 HTU.moveRegionAndWait(meta.getRegionInfo(), hrsOther.getServerName()); 154 // Assert that there is a ReplicationSource in both places now. 155 assertTrue(isMetaRegionReplicaReplicationSource(hrs)); 156 assertTrue(isMetaRegionReplicaReplicationSource(hrsOther)); 157 // Replicate to show stuff still works. 158 testHBaseMetaReplicatesOneRow(1); 159 // Now pretend a few hours have gone by... roll the meta WAL in original location... Move the 160 // meta back and retry replication. See if it works. 161 hrs.getWAL(meta.getRegionInfo()).rollWriter(true); 162 testHBaseMetaReplicatesOneRow(2); 163 hrs.getWAL(meta.getRegionInfo()).rollWriter(true); 164 testHBaseMetaReplicatesOneRow(3); 165 } 166 167 /** 168 * Test meta region replica replication. Create some tables and see if replicas pick up the 169 * additions. 170 */ 171 private void testHBaseMetaReplicatesOneRow(int i) throws Exception { 172 waitForMetaReplicasToOnline(); 173 try (Table table = HTU.createTable(TableName.valueOf(this.name.getMethodName() + "_" + i), 174 HConstants.CATALOG_FAMILY)) { 175 verifyReplication(TableName.META_TABLE_NAME, numOfMetaReplica, getMetaCells(table.getName())); 176 } 177 } 178 179 /** Returns Whether the special meta region replica peer is enabled on <code>hrs</code> */ 180 private boolean isMetaRegionReplicaReplicationSource(HRegionServer hrs) { 181 return hrs.getReplicationSourceService().getReplicationManager().catalogReplicationSource.get() 182 != null; 183 } 184 185 /** 186 * Test meta region replica replication. Create some tables and see if replicas pick up the 187 * additions. 188 */ 189 @Test 190 public void testHBaseMetaReplicates() throws Exception { 191 try (Table table = HTU.createTable(TableName.valueOf(this.name.getMethodName() + "_0"), 192 HConstants.CATALOG_FAMILY, 193 Arrays.copyOfRange(HBaseTestingUtility.KEYS, 1, HBaseTestingUtility.KEYS.length))) { 194 verifyReplication(TableName.META_TABLE_NAME, numOfMetaReplica, getMetaCells(table.getName())); 195 } 196 try (Table table = HTU.createTable(TableName.valueOf(this.name.getMethodName() + "_1"), 197 HConstants.CATALOG_FAMILY, 198 Arrays.copyOfRange(HBaseTestingUtility.KEYS, 1, HBaseTestingUtility.KEYS.length))) { 199 verifyReplication(TableName.META_TABLE_NAME, numOfMetaReplica, getMetaCells(table.getName())); 200 // Try delete. 201 HTU.deleteTableIfAny(table.getName()); 202 verifyDeletedReplication(TableName.META_TABLE_NAME, numOfMetaReplica, table.getName()); 203 } 204 } 205 206 @Test 207 public void testCatalogReplicaReplicationWithFlushAndCompaction() throws Exception { 208 Connection connection = ConnectionFactory.createConnection(HTU.getConfiguration()); 209 TableName tableName = TableName.valueOf("hbase:meta"); 210 Table table = connection.getTable(tableName); 211 try { 212 // load the data to the table 213 for (int i = 0; i < 5; i++) { 214 LOG.info("Writing data from " + i * 1000 + " to " + (i * 1000 + 1000)); 215 HTU.loadNumericRows(table, HConstants.CATALOG_FAMILY, i * 1000, i * 1000 + 1000); 216 LOG.info("flushing table"); 217 HTU.flush(tableName); 218 LOG.info("compacting table"); 219 if (i < 4) { 220 HTU.compact(tableName, false); 221 } 222 } 223 224 verifyReplication(tableName, numOfMetaReplica, 0, 5000, HConstants.CATALOG_FAMILY); 225 } finally { 226 table.close(); 227 connection.close(); 228 } 229 } 230 231 @Test 232 public void testCatalogReplicaReplicationWALRolledAndDeleted() throws Exception { 233 TableName tableName = TableName.valueOf("hbase:meta"); 234 try (Connection connection = ConnectionFactory.createConnection(HTU.getConfiguration()); 235 Table table = connection.getTable(tableName)) { 236 MiniHBaseCluster cluster = HTU.getHBaseCluster(); 237 cluster.getMaster().balanceSwitch(false); 238 HRegionServer hrs = cluster.getRegionServer(cluster.getServerHoldingMeta()); 239 ReplicationSource source = (ReplicationSource) hrs.getReplicationSourceService() 240 .getReplicationManager().catalogReplicationSource.get(); 241 ((ReplicationPeerImpl) source.replicationPeer).setPeerState(false); 242 // there's small chance source reader has passed the peer state check but not yet read the 243 // wal, which could allow it to read some added entries before the wal gets deleted, 244 // so we are making sure here we only proceed once the reader loop has managed to 245 // detect the peer is disabled. 246 HTU.waitFor(2000, 100, true, () -> { 247 MutableObject<Boolean> readerWaiting = new MutableObject<>(true); 248 source.logQueue.getQueues().keySet() 249 .forEach(w -> readerWaiting.setValue(readerWaiting.getValue() 250 && source.workerThreads.get(w).entryReader.waitingPeerEnabled.get())); 251 return readerWaiting.getValue(); 252 }); 253 // load the data to the table 254 for (int i = 0; i < 5; i++) { 255 LOG.info("Writing data from " + i * 1000 + " to " + (i * 1000 + 1000)); 256 HTU.loadNumericRows(table, HConstants.CATALOG_FAMILY, i * 1000, i * 1000 + 1000); 257 LOG.info("flushing table"); 258 HTU.flush(tableName); 259 LOG.info("compacting table"); 260 if (i < 4) { 261 HTU.compact(tableName, false); 262 } 263 } 264 HTU.getHBaseCluster().getMaster().getLogCleaner().triggerCleanerNow().get(1, 265 TimeUnit.SECONDS); 266 ((ReplicationPeerImpl) source.replicationPeer).setPeerState(true); 267 // now loads more data without flushing nor compacting 268 for (int i = 5; i < 10; i++) { 269 LOG.info("Writing data from " + i * 1000 + " to " + (i * 1000 + 1000)); 270 HTU.loadNumericRows(table, HConstants.CATALOG_FAMILY, i * 1000, i * 1000 + 1000); 271 } 272 verifyReplication(tableName, numOfMetaReplica, 0, 10000, HConstants.CATALOG_FAMILY); 273 } 274 } 275 276 @Test 277 public void testCatalogReplicaReplicationWithReplicaMoved() throws Exception { 278 MiniHBaseCluster cluster = HTU.getMiniHBaseCluster(); 279 HRegionServer hrs = cluster.getRegionServer(cluster.getServerHoldingMeta()); 280 281 HRegionServer hrsMetaReplica = null; 282 HRegionServer hrsNoMetaReplica = null; 283 HRegionServer server = null; 284 Region metaReplica = null; 285 boolean hostingMeta; 286 287 for (int i = 0; i < cluster.getNumLiveRegionServers(); i++) { 288 server = cluster.getRegionServer(i); 289 hostingMeta = false; 290 if (server == hrs) { 291 continue; 292 } 293 for (Region region : server.getOnlineRegionsLocalContext()) { 294 if (region.getRegionInfo().isMetaRegion()) { 295 if (metaReplica == null) { 296 metaReplica = region; 297 } 298 hostingMeta = true; 299 break; 300 } 301 } 302 if (!hostingMeta) { 303 hrsNoMetaReplica = server; 304 } 305 } 306 307 Connection connection = ConnectionFactory.createConnection(HTU.getConfiguration()); 308 TableName tableName = TableName.valueOf("hbase:meta"); 309 Table table = connection.getTable(tableName); 310 try { 311 // load the data to the table 312 for (int i = 0; i < 5; i++) { 313 LOG.info("Writing data from " + i * 1000 + " to " + (i * 1000 + 1000)); 314 HTU.loadNumericRows(table, HConstants.CATALOG_FAMILY, i * 1000, i * 1000 + 1000); 315 if (i == 0) { 316 HTU.moveRegionAndWait(metaReplica.getRegionInfo(), hrsNoMetaReplica.getServerName()); 317 } 318 } 319 320 verifyReplication(tableName, numOfMetaReplica, 0, 5000, HConstants.CATALOG_FAMILY); 321 } finally { 322 table.close(); 323 connection.close(); 324 } 325 } 326 327 protected void verifyReplication(TableName tableName, int regionReplication, final int startRow, 328 final int endRow, final byte[] family) throws Exception { 329 verifyReplication(tableName, regionReplication, startRow, endRow, family, true); 330 } 331 332 private void verifyReplication(TableName tableName, int regionReplication, final int startRow, 333 final int endRow, final byte[] family, final boolean present) throws Exception { 334 // find the regions 335 final Region[] regions = new Region[regionReplication]; 336 337 for (int i = 0; i < NB_SERVERS; i++) { 338 HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(i); 339 List<HRegion> onlineRegions = rs.getRegions(tableName); 340 for (HRegion region : onlineRegions) { 341 regions[region.getRegionInfo().getReplicaId()] = region; 342 } 343 } 344 345 for (Region region : regions) { 346 assertNotNull(region); 347 } 348 349 for (int i = 1; i < regionReplication; i++) { 350 final Region region = regions[i]; 351 // wait until all the data is replicated to all secondary regions 352 Waiter.waitFor(HTU.getConfiguration(), 90000, 1000, new Waiter.Predicate<Exception>() { 353 @Override 354 public boolean evaluate() throws Exception { 355 LOG.info("verifying replication for region replica:" + region.getRegionInfo()); 356 try { 357 HTU.verifyNumericRows(region, family, startRow, endRow, present); 358 } catch (Throwable ex) { 359 LOG.warn("Verification from secondary region is not complete yet", ex); 360 // still wait 361 return false; 362 } 363 return true; 364 } 365 }); 366 } 367 } 368 369 /** 370 * Replicas come online after primary. 371 */ 372 private void waitForMetaReplicasToOnline() throws IOException { 373 final RegionLocator regionLocator = 374 HTU.getConnection().getRegionLocator(TableName.META_TABLE_NAME); 375 HTU.waitFor(10000, 376 // getRegionLocations returns an entry for each replica but if unassigned, entry is null. 377 // Pass reload to force us to skip cache else it just keeps returning default. 378 () -> regionLocator.getRegionLocations(HConstants.EMPTY_START_ROW, true).stream() 379 .filter(Objects::nonNull).count() >= numOfMetaReplica); 380 List<HRegionLocation> locations = regionLocator.getRegionLocations(HConstants.EMPTY_START_ROW); 381 LOG.info("Found locations {}", locations); 382 assertEquals(numOfMetaReplica, locations.size()); 383 } 384 385 /** 386 * Scan hbase:meta for <code>tableName</code> content. 387 */ 388 private List<Result> getMetaCells(TableName tableName) throws IOException { 389 final List<Result> results = new ArrayList<>(); 390 MetaTableAccessor.Visitor visitor = new MetaTableAccessor.Visitor() { 391 @Override 392 public boolean visit(Result r) throws IOException { 393 results.add(r); 394 return true; 395 } 396 }; 397 MetaTableAccessor.scanMetaForTableRegions(HTU.getConnection(), visitor, tableName); 398 return results; 399 } 400 401 /** Returns All Regions for tableName including Replicas. */ 402 private Region[] getAllRegions(TableName tableName, int replication) { 403 final Region[] regions = new Region[replication]; 404 for (int i = 0; i < NB_SERVERS; i++) { 405 HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(i); 406 List<HRegion> onlineRegions = rs.getRegions(tableName); 407 for (HRegion region : onlineRegions) { 408 regions[region.getRegionInfo().getReplicaId()] = region; 409 } 410 } 411 for (Region region : regions) { 412 assertNotNull(region); 413 } 414 return regions; 415 } 416 417 private Region getOneRegion(TableName tableName) { 418 for (int i = 0; i < NB_SERVERS; i++) { 419 HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(i); 420 List<HRegion> onlineRegions = rs.getRegions(tableName); 421 if (onlineRegions.size() > 1) { 422 return onlineRegions.get(0); 423 } 424 } 425 return null; 426 } 427 428 /** 429 * Verify when a Table is deleted from primary, then there are no references in replicas (because 430 * they get the delete of the table rows too). 431 */ 432 private void verifyDeletedReplication(TableName tableName, int regionReplication, 433 final TableName deletedTableName) { 434 final Region[] regions = getAllRegions(tableName, regionReplication); 435 436 // Start count at '1' so we skip default, primary replica and only look at secondaries. 437 for (int i = 1; i < regionReplication; i++) { 438 final Region region = regions[i]; 439 // wait until all the data is replicated to all secondary regions 440 Waiter.waitFor(HTU.getConfiguration(), 30000, 1000, new Waiter.Predicate<Exception>() { 441 @Override 442 public boolean evaluate() throws Exception { 443 LOG.info("Verifying replication for region replica {}", region.getRegionInfo()); 444 try (RegionScanner rs = region.getScanner(new Scan())) { 445 List<Cell> cells = new ArrayList<>(); 446 while (rs.next(cells)) { 447 continue; 448 } 449 return doesNotContain(cells, deletedTableName); 450 } catch (Throwable ex) { 451 LOG.warn("Verification from secondary region is not complete yet", ex); 452 // still wait 453 return false; 454 } 455 } 456 }); 457 } 458 } 459 460 /** 461 * Cells are from hbase:meta replica so will start w/ 'tableName,'; i.e. the tablename followed by 462 * HConstants.DELIMITER. Make sure the deleted table is no longer present in passed 463 * <code>cells</code>. 464 */ 465 private boolean doesNotContain(List<Cell> cells, TableName tableName) { 466 for (Cell cell : cells) { 467 String row = Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 468 if (row.startsWith(tableName.toString() + HConstants.DELIMITER)) { 469 return false; 470 } 471 } 472 return true; 473 } 474 475 /** 476 * Verify Replicas have results (exactly). 477 */ 478 private void verifyReplication(TableName tableName, int regionReplication, 479 List<Result> contains) { 480 final Region[] regions = getAllRegions(tableName, regionReplication); 481 482 // Start count at '1' so we skip default, primary replica and only look at secondaries. 483 for (int i = 1; i < regionReplication; i++) { 484 final Region region = regions[i]; 485 // wait until all the data is replicated to all secondary regions 486 Waiter.waitFor(HTU.getConfiguration(), 30000, 1000, new Waiter.Predicate<Exception>() { 487 @Override 488 public boolean evaluate() throws Exception { 489 LOG.info("Verifying replication for region replica {}", region.getRegionInfo()); 490 try (RegionScanner rs = region.getScanner(new Scan())) { 491 List<Cell> cells = new ArrayList<>(); 492 while (rs.next(cells)) { 493 continue; 494 } 495 return contains(contains, cells); 496 } catch (Throwable ex) { 497 LOG.warn("Verification from secondary region is not complete yet", ex); 498 // still wait 499 return false; 500 } 501 } 502 }); 503 } 504 } 505 506 /** 507 * Presumes sorted Cells. Verify that <code>cells</code> has <code>contains</code> at least. 508 */ 509 static boolean contains(List<Result> contains, List<Cell> cells) throws IOException { 510 CellScanner containsScanner = CellUtil.createCellScanner(contains); 511 CellScanner cellsScanner = CellUtil.createCellScanner(cells); 512 int matches = 0; 513 int count = 0; 514 while (containsScanner.advance()) { 515 while (cellsScanner.advance()) { 516 count++; 517 LOG.info("{} {}", containsScanner.current(), cellsScanner.current()); 518 if (containsScanner.current().equals(cellsScanner.current())) { 519 matches++; 520 break; 521 } 522 } 523 } 524 return !containsScanner.advance() && matches >= 1 && count >= matches && count == cells.size(); 525 } 526 527 private void doNGets(final Table table, final byte[][] keys) throws Exception { 528 for (byte[] key : keys) { 529 Result r = table.get(new Get(key)); 530 assertArrayEquals(VALUE, r.getValue(HConstants.CATALOG_FAMILY, HConstants.CATALOG_FAMILY)); 531 } 532 } 533 534 private void primaryNoChangeReplicaIncrease(final long[] before, final long[] after) { 535 assertEquals(before[RegionInfo.DEFAULT_REPLICA_ID], after[RegionInfo.DEFAULT_REPLICA_ID]); 536 537 for (int i = 1; i < after.length; i++) { 538 assertTrue(after[i] > before[i]); 539 } 540 } 541 542 private void primaryIncreaseReplicaNoChange(final long[] before, final long[] after) { 543 // There are read requests increase for primary meta replica. 544 assertTrue(after[RegionInfo.DEFAULT_REPLICA_ID] > before[RegionInfo.DEFAULT_REPLICA_ID]); 545 546 // No change for replica regions 547 for (int i = 1; i < after.length; i++) { 548 assertEquals(before[i], after[i]); 549 } 550 } 551 552 private void primaryMayIncreaseReplicaNoChange(final long[] before, final long[] after) { 553 // For primary meta replica, scan request may increase. No change for replica meta regions. 554 assertTrue(after[RegionInfo.DEFAULT_REPLICA_ID] >= before[RegionInfo.DEFAULT_REPLICA_ID]); 555 556 // No change for replica regions 557 for (int i = 1; i < after.length; i++) { 558 assertEquals(before[i], after[i]); 559 } 560 } 561 562 private void primaryIncreaseReplicaIncrease(final long[] before, final long[] after) { 563 // There are read requests increase for all meta replica regions, 564 for (int i = 0; i < after.length; i++) { 565 assertTrue(after[i] > before[i]); 566 } 567 } 568 569 private void getMetaReplicaReadRequests(final Region[] metaRegions, final long[] counters) { 570 int i = 0; 571 for (Region r : metaRegions) { 572 LOG.info("read request for region {} is {}", r, r.getReadRequestsCount()); 573 counters[i] = r.getReadRequestsCount(); 574 i++; 575 } 576 } 577 578 @Test 579 public void testHBaseMetaReplicaGets() throws Exception { 580 581 TableName tn = TableName.valueOf(this.name.getMethodName()); 582 final Region[] metaRegions = getAllRegions(TableName.META_TABLE_NAME, numOfMetaReplica); 583 long[] readReqsForMetaReplicas = new long[numOfMetaReplica]; 584 long[] readReqsForMetaReplicasAfterGet = new long[numOfMetaReplica]; 585 long[] readReqsForMetaReplicasAfterGetAllLocations = new long[numOfMetaReplica]; 586 long[] readReqsForMetaReplicasAfterMove = new long[numOfMetaReplica]; 587 long[] readReqsForMetaReplicasAfterSecondMove = new long[numOfMetaReplica]; 588 long[] readReqsForMetaReplicasAfterThirdGet = new long[numOfMetaReplica]; 589 Region userRegion = null; 590 HRegionServer srcRs = null; 591 HRegionServer destRs = null; 592 593 try (Table table = HTU.createTable(tn, HConstants.CATALOG_FAMILY, 594 Arrays.copyOfRange(HBaseTestingUtility.KEYS, 1, HBaseTestingUtility.KEYS.length))) { 595 verifyReplication(TableName.META_TABLE_NAME, numOfMetaReplica, getMetaCells(table.getName())); 596 // load different values 597 HTU.loadTable(table, new byte[][] { HConstants.CATALOG_FAMILY }, VALUE); 598 for (int i = 0; i < NB_SERVERS; i++) { 599 HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(i); 600 List<HRegion> onlineRegions = rs.getRegions(tn); 601 if (onlineRegions.size() > 0) { 602 userRegion = onlineRegions.get(0); 603 srcRs = rs; 604 if (i > 0) { 605 destRs = HTU.getMiniHBaseCluster().getRegionServer(0); 606 } else { 607 destRs = HTU.getMiniHBaseCluster().getRegionServer(1); 608 } 609 } 610 } 611 612 getMetaReplicaReadRequests(metaRegions, readReqsForMetaReplicas); 613 614 Configuration c = new Configuration(HTU.getConfiguration()); 615 c.set(LOCATOR_META_REPLICAS_MODE, "LoadBalance"); 616 Connection connection = ConnectionFactory.createConnection(c); 617 Table tableForGet = connection.getTable(tn); 618 byte[][] getRows = new byte[HBaseTestingUtility.KEYS.length][]; 619 620 int i = 0; 621 for (byte[] key : HBaseTestingUtility.KEYS) { 622 getRows[i] = key; 623 i++; 624 } 625 getRows[0] = Bytes.toBytes("aaa"); 626 doNGets(tableForGet, getRows); 627 628 getMetaReplicaReadRequests(metaRegions, readReqsForMetaReplicasAfterGet); 629 630 // There are more reads against all meta replica regions, including the primary region. 631 primaryIncreaseReplicaIncrease(readReqsForMetaReplicas, readReqsForMetaReplicasAfterGet); 632 633 RegionLocator locator = tableForGet.getRegionLocator(); 634 635 for (int j = 0; j < numOfMetaReplica * 3; j++) { 636 locator.getAllRegionLocations(); 637 } 638 639 getMetaReplicaReadRequests(metaRegions, readReqsForMetaReplicasAfterGetAllLocations); 640 primaryIncreaseReplicaIncrease(readReqsForMetaReplicasAfterGet, 641 readReqsForMetaReplicasAfterGetAllLocations); 642 643 // move one of regions so it meta cache may be invalid. 644 HTU.moveRegionAndWait(userRegion.getRegionInfo(), destRs.getServerName()); 645 646 doNGets(tableForGet, getRows); 647 648 getMetaReplicaReadRequests(metaRegions, readReqsForMetaReplicasAfterMove); 649 650 // There are read requests increase for primary meta replica. 651 // For rest of meta replicas, there is no change as regionMove will tell the new location 652 primaryIncreaseReplicaNoChange(readReqsForMetaReplicasAfterGetAllLocations, 653 readReqsForMetaReplicasAfterMove); 654 // Move region again. 655 HTU.moveRegionAndWait(userRegion.getRegionInfo(), srcRs.getServerName()); 656 657 // Wait until moveRegion cache timeout. 658 while (destRs.getMovedRegion(userRegion.getRegionInfo().getEncodedName()) != null) { 659 Thread.sleep(1000); 660 } 661 662 getMetaReplicaReadRequests(metaRegions, readReqsForMetaReplicasAfterSecondMove); 663 664 // There may be read requests increase for primary meta replica. 665 // For rest of meta replicas, there is no change. 666 primaryMayIncreaseReplicaNoChange(readReqsForMetaReplicasAfterMove, 667 readReqsForMetaReplicasAfterSecondMove); 668 669 doNGets(tableForGet, getRows); 670 671 getMetaReplicaReadRequests(metaRegions, readReqsForMetaReplicasAfterThirdGet); 672 673 // Since it gets RegionNotServedException, it will go to primary for the next lookup. 674 // There are read requests increase for primary meta replica. 675 // For rest of meta replicas, there is no change. 676 primaryIncreaseReplicaNoChange(readReqsForMetaReplicasAfterSecondMove, 677 readReqsForMetaReplicasAfterThirdGet); 678 } 679 } 680}