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; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNotNull; 023import static org.junit.Assert.assertNull; 024import static org.junit.Assert.assertTrue; 025import static org.mockito.Matchers.anyObject; 026import static org.mockito.Mockito.doReturn; 027import static org.mockito.Mockito.mock; 028import static org.mockito.Mockito.reset; 029import static org.mockito.Mockito.times; 030import static org.mockito.Mockito.verify; 031 032import java.io.IOException; 033import java.util.List; 034import java.util.Random; 035import org.apache.hadoop.conf.Configuration; 036import org.apache.hadoop.hbase.client.Admin; 037import org.apache.hadoop.hbase.client.Connection; 038import org.apache.hadoop.hbase.client.ConnectionFactory; 039import org.apache.hadoop.hbase.client.Get; 040import org.apache.hadoop.hbase.client.RegionInfo; 041import org.apache.hadoop.hbase.client.RegionInfoBuilder; 042import org.apache.hadoop.hbase.client.RegionLocator; 043import org.apache.hadoop.hbase.client.Result; 044import org.apache.hadoop.hbase.client.Table; 045import org.apache.hadoop.hbase.ipc.CallRunner; 046import org.apache.hadoop.hbase.ipc.DelegatingRpcScheduler; 047import org.apache.hadoop.hbase.ipc.PriorityFunction; 048import org.apache.hadoop.hbase.ipc.RpcScheduler; 049import org.apache.hadoop.hbase.regionserver.HRegionServer; 050import org.apache.hadoop.hbase.regionserver.RSRpcServices; 051import org.apache.hadoop.hbase.regionserver.SimpleRpcSchedulerFactory; 052import org.apache.hadoop.hbase.testclassification.MediumTests; 053import org.apache.hadoop.hbase.testclassification.MiscTests; 054import org.apache.hadoop.hbase.util.Bytes; 055import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 056import org.apache.hadoop.hbase.util.ManualEnvironmentEdge; 057import org.apache.hadoop.hbase.util.Pair; 058import org.apache.hadoop.hbase.zookeeper.MetaTableLocator; 059import org.junit.AfterClass; 060import org.junit.Assert; 061import org.junit.BeforeClass; 062import org.junit.ClassRule; 063import org.junit.Rule; 064import org.junit.Test; 065import org.junit.experimental.categories.Category; 066import org.junit.rules.TestName; 067import org.slf4j.Logger; 068import org.slf4j.LoggerFactory; 069 070import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 071 072/** 073 * Test {@link org.apache.hadoop.hbase.MetaTableAccessor}. 074 */ 075@Category({MiscTests.class, MediumTests.class}) 076@SuppressWarnings("deprecation") 077public class TestMetaTableAccessor { 078 079 @ClassRule 080 public static final HBaseClassTestRule CLASS_RULE = 081 HBaseClassTestRule.forClass(TestMetaTableAccessor.class); 082 083 private static final Logger LOG = LoggerFactory.getLogger(TestMetaTableAccessor.class); 084 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 085 private static Connection connection; 086 private Random random = new Random(); 087 088 @Rule 089 public TestName name = new TestName(); 090 091 @BeforeClass public static void beforeClass() throws Exception { 092 UTIL.startMiniCluster(3); 093 094 Configuration c = new Configuration(UTIL.getConfiguration()); 095 // Tests to 4 retries every 5 seconds. Make it try every 1 second so more 096 // responsive. 1 second is default as is ten retries. 097 c.setLong("hbase.client.pause", 1000); 098 c.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 10); 099 connection = ConnectionFactory.createConnection(c); 100 } 101 102 @AfterClass public static void afterClass() throws Exception { 103 connection.close(); 104 UTIL.shutdownMiniCluster(); 105 } 106 107 /** 108 * Does {@link MetaTableAccessor#getRegion(Connection, byte[])} and a write 109 * against hbase:meta while its hosted server is restarted to prove our retrying 110 * works. 111 */ 112 @Test public void testRetrying() 113 throws IOException, InterruptedException { 114 final TableName tableName = TableName.valueOf(name.getMethodName()); 115 LOG.info("Started " + tableName); 116 Table t = UTIL.createMultiRegionTable(tableName, HConstants.CATALOG_FAMILY); 117 int regionCount = -1; 118 try (RegionLocator r = UTIL.getConnection().getRegionLocator(tableName)) { 119 regionCount = r.getStartKeys().length; 120 } 121 // Test it works getting a region from just made user table. 122 final List<RegionInfo> regions = 123 testGettingTableRegions(connection, tableName, regionCount); 124 MetaTask reader = new MetaTask(connection, "reader") { 125 @Override 126 void metaTask() throws Throwable { 127 testGetRegion(connection, regions.get(0)); 128 LOG.info("Read " + regions.get(0).getEncodedName()); 129 } 130 }; 131 MetaTask writer = new MetaTask(connection, "writer") { 132 @Override 133 void metaTask() throws Throwable { 134 MetaTableAccessor.addRegionToMeta(connection, regions.get(0)); 135 LOG.info("Wrote " + regions.get(0).getEncodedName()); 136 } 137 }; 138 reader.start(); 139 writer.start(); 140 141 // We're gonna check how it takes. If it takes too long, we will consider 142 // it as a fail. We can't put that in the @Test tag as we want to close 143 // the threads nicely 144 final long timeOut = 180000; 145 long startTime = System.currentTimeMillis(); 146 147 try { 148 // Make sure reader and writer are working. 149 assertTrue(reader.isProgressing()); 150 assertTrue(writer.isProgressing()); 151 152 // Kill server hosting meta -- twice . See if our reader/writer ride over the 153 // meta moves. They'll need to retry. 154 for (int i = 0; i < 2; i++) { 155 LOG.info("Restart=" + i); 156 UTIL.ensureSomeRegionServersAvailable(2); 157 int index = -1; 158 do { 159 index = UTIL.getMiniHBaseCluster().getServerWithMeta(); 160 } while (index == -1 && 161 startTime + timeOut < System.currentTimeMillis()); 162 163 if (index != -1){ 164 UTIL.getMiniHBaseCluster().abortRegionServer(index); 165 UTIL.getMiniHBaseCluster().waitOnRegionServer(index); 166 } 167 } 168 169 assertTrue("reader: " + reader.toString(), reader.isProgressing()); 170 assertTrue("writer: " + writer.toString(), writer.isProgressing()); 171 } catch (IOException e) { 172 throw e; 173 } finally { 174 reader.stop = true; 175 writer.stop = true; 176 reader.join(); 177 writer.join(); 178 t.close(); 179 } 180 long exeTime = System.currentTimeMillis() - startTime; 181 assertTrue("Timeout: test took " + exeTime / 1000 + " sec", exeTime < timeOut); 182 } 183 184 /** 185 * Thread that runs a MetaTableAccessor task until asked stop. 186 */ 187 abstract static class MetaTask extends Thread { 188 boolean stop = false; 189 int count = 0; 190 Throwable t = null; 191 final Connection connection; 192 193 MetaTask(final Connection connection, final String name) { 194 super(name); 195 this.connection = connection; 196 } 197 198 @Override 199 public void run() { 200 try { 201 while(!this.stop) { 202 LOG.info("Before " + this.getName()+ ", count=" + this.count); 203 metaTask(); 204 this.count += 1; 205 LOG.info("After " + this.getName() + ", count=" + this.count); 206 Thread.sleep(100); 207 } 208 } catch (Throwable t) { 209 LOG.info(this.getName() + " failed", t); 210 this.t = t; 211 } 212 } 213 214 boolean isProgressing() throws InterruptedException { 215 int currentCount = this.count; 216 while(currentCount == this.count) { 217 if (!isAlive()) return false; 218 if (this.t != null) return false; 219 Thread.sleep(10); 220 } 221 return true; 222 } 223 224 @Override 225 public String toString() { 226 return "count=" + this.count + ", t=" + 227 (this.t == null? "null": this.t.toString()); 228 } 229 230 abstract void metaTask() throws Throwable; 231 } 232 233 @Test public void testGetRegionsFromMetaTable() 234 throws IOException, InterruptedException { 235 List<RegionInfo> regions = 236 new MetaTableLocator().getMetaRegions(UTIL.getZooKeeperWatcher()); 237 assertTrue(regions.size() >= 1); 238 assertTrue(new MetaTableLocator().getMetaRegionsAndLocations( 239 UTIL.getZooKeeperWatcher()).size() >= 1); 240 } 241 242 @Test public void testTableExists() throws IOException { 243 final TableName tableName = TableName.valueOf(name.getMethodName()); 244 assertFalse(MetaTableAccessor.tableExists(connection, tableName)); 245 UTIL.createTable(tableName, HConstants.CATALOG_FAMILY); 246 assertTrue(MetaTableAccessor.tableExists(connection, tableName)); 247 Admin admin = UTIL.getAdmin(); 248 admin.disableTable(tableName); 249 admin.deleteTable(tableName); 250 assertFalse(MetaTableAccessor.tableExists(connection, tableName)); 251 assertTrue(MetaTableAccessor.tableExists(connection, 252 TableName.META_TABLE_NAME)); 253 UTIL.createTable(tableName, HConstants.CATALOG_FAMILY); 254 assertTrue(MetaTableAccessor.tableExists(connection, tableName)); 255 admin.disableTable(tableName); 256 admin.deleteTable(tableName); 257 assertFalse(MetaTableAccessor.tableExists(connection, tableName)); 258 } 259 260 @Test public void testGetRegion() throws IOException, InterruptedException { 261 final String name = this.name.getMethodName(); 262 LOG.info("Started " + name); 263 // Test get on non-existent region. 264 Pair<RegionInfo, ServerName> pair = 265 MetaTableAccessor.getRegion(connection, Bytes.toBytes("nonexistent-region")); 266 assertNull(pair); 267 LOG.info("Finished " + name); 268 } 269 270 // Test for the optimization made in HBASE-3650 271 @Test public void testScanMetaForTable() 272 throws IOException, InterruptedException { 273 final TableName tableName = TableName.valueOf(name.getMethodName()); 274 LOG.info("Started " + tableName); 275 276 /** Create 2 tables 277 - testScanMetaForTable 278 - testScanMetaForTablf 279 **/ 280 281 UTIL.createTable(tableName, HConstants.CATALOG_FAMILY); 282 // name that is +1 greater than the first one (e+1=f) 283 TableName greaterName = 284 TableName.valueOf("testScanMetaForTablf"); 285 UTIL.createTable(greaterName, HConstants.CATALOG_FAMILY); 286 287 // Now make sure we only get the regions from 1 of the tables at a time 288 289 assertEquals(1, MetaTableAccessor.getTableRegions(connection, tableName).size()); 290 assertEquals(1, MetaTableAccessor.getTableRegions(connection, greaterName).size()); 291 } 292 293 private static List<RegionInfo> testGettingTableRegions(final Connection connection, 294 final TableName name, final int regionCount) 295 throws IOException, InterruptedException { 296 List<RegionInfo> regions = MetaTableAccessor.getTableRegions(connection, name); 297 assertEquals(regionCount, regions.size()); 298 Pair<RegionInfo, ServerName> pair = 299 MetaTableAccessor.getRegion(connection, regions.get(0).getRegionName()); 300 assertEquals(regions.get(0).getEncodedName(), 301 pair.getFirst().getEncodedName()); 302 return regions; 303 } 304 305 private static void testGetRegion(final Connection connection, 306 final RegionInfo region) 307 throws IOException, InterruptedException { 308 Pair<RegionInfo, ServerName> pair = 309 MetaTableAccessor.getRegion(connection, region.getRegionName()); 310 assertEquals(region.getEncodedName(), 311 pair.getFirst().getEncodedName()); 312 } 313 314 @Test 315 public void testParseReplicaIdFromServerColumn() { 316 String column1 = HConstants.SERVER_QUALIFIER_STR; 317 assertEquals(0, MetaTableAccessor.parseReplicaIdFromServerColumn(Bytes.toBytes(column1))); 318 String column2 = column1 + MetaTableAccessor.META_REPLICA_ID_DELIMITER; 319 assertEquals(-1, MetaTableAccessor.parseReplicaIdFromServerColumn(Bytes.toBytes(column2))); 320 String column3 = column2 + "00"; 321 assertEquals(-1, MetaTableAccessor.parseReplicaIdFromServerColumn(Bytes.toBytes(column3))); 322 String column4 = column3 + "2A"; 323 assertEquals(42, MetaTableAccessor.parseReplicaIdFromServerColumn(Bytes.toBytes(column4))); 324 String column5 = column4 + "2A"; 325 assertEquals(-1, MetaTableAccessor.parseReplicaIdFromServerColumn(Bytes.toBytes(column5))); 326 String column6 = HConstants.STARTCODE_QUALIFIER_STR; 327 assertEquals(-1, MetaTableAccessor.parseReplicaIdFromServerColumn(Bytes.toBytes(column6))); 328 } 329 330 @Test 331 public void testMetaReaderGetColumnMethods() { 332 Assert.assertArrayEquals(HConstants.SERVER_QUALIFIER, MetaTableAccessor.getServerColumn(0)); 333 Assert.assertArrayEquals(Bytes.toBytes(HConstants.SERVER_QUALIFIER_STR 334 + MetaTableAccessor.META_REPLICA_ID_DELIMITER + "002A"), 335 MetaTableAccessor.getServerColumn(42)); 336 337 Assert.assertArrayEquals(HConstants.STARTCODE_QUALIFIER, 338 MetaTableAccessor.getStartCodeColumn(0)); 339 Assert.assertArrayEquals(Bytes.toBytes(HConstants.STARTCODE_QUALIFIER_STR 340 + MetaTableAccessor.META_REPLICA_ID_DELIMITER + "002A"), 341 MetaTableAccessor.getStartCodeColumn(42)); 342 343 Assert.assertArrayEquals(HConstants.SEQNUM_QUALIFIER, 344 MetaTableAccessor.getSeqNumColumn(0)); 345 Assert.assertArrayEquals(Bytes.toBytes(HConstants.SEQNUM_QUALIFIER_STR 346 + MetaTableAccessor.META_REPLICA_ID_DELIMITER + "002A"), 347 MetaTableAccessor.getSeqNumColumn(42)); 348 } 349 350 @Test 351 public void testMetaLocationsForRegionReplicas() throws IOException { 352 ServerName serverName0 = ServerName.valueOf("foo", 60010, random.nextLong()); 353 ServerName serverName1 = ServerName.valueOf("bar", 60010, random.nextLong()); 354 ServerName serverName100 = ServerName.valueOf("baz", 60010, random.nextLong()); 355 356 long regionId = System.currentTimeMillis(); 357 RegionInfo primary = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 358 .setStartKey(HConstants.EMPTY_START_ROW) 359 .setEndKey(HConstants.EMPTY_END_ROW) 360 .setSplit(false) 361 .setRegionId(regionId) 362 .setReplicaId(0) 363 .build(); 364 RegionInfo replica1 = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 365 .setStartKey(HConstants.EMPTY_START_ROW) 366 .setEndKey(HConstants.EMPTY_END_ROW) 367 .setSplit(false) 368 .setRegionId(regionId) 369 .setReplicaId(1) 370 .build(); 371 RegionInfo replica100 = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 372 .setStartKey(HConstants.EMPTY_START_ROW) 373 .setEndKey(HConstants.EMPTY_END_ROW) 374 .setSplit(false) 375 .setRegionId(regionId) 376 .setReplicaId(100) 377 .build(); 378 379 long seqNum0 = random.nextLong(); 380 long seqNum1 = random.nextLong(); 381 long seqNum100 = random.nextLong(); 382 383 try (Table meta = MetaTableAccessor.getMetaHTable(connection)) { 384 MetaTableAccessor.updateRegionLocation(connection, primary, serverName0, seqNum0, 385 EnvironmentEdgeManager.currentTime()); 386 387 // assert that the server, startcode and seqNum columns are there for the primary region 388 assertMetaLocation(meta, primary.getRegionName(), serverName0, seqNum0, 0, true); 389 390 // add replica = 1 391 MetaTableAccessor.updateRegionLocation(connection, replica1, serverName1, seqNum1, 392 EnvironmentEdgeManager.currentTime()); 393 // check whether the primary is still there 394 assertMetaLocation(meta, primary.getRegionName(), serverName0, seqNum0, 0, true); 395 // now check for replica 1 396 assertMetaLocation(meta, primary.getRegionName(), serverName1, seqNum1, 1, true); 397 398 // add replica = 1 399 MetaTableAccessor.updateRegionLocation(connection, replica100, serverName100, seqNum100, 400 EnvironmentEdgeManager.currentTime()); 401 // check whether the primary is still there 402 assertMetaLocation(meta, primary.getRegionName(), serverName0, seqNum0, 0, true); 403 // check whether the replica 1 is still there 404 assertMetaLocation(meta, primary.getRegionName(), serverName1, seqNum1, 1, true); 405 // now check for replica 1 406 assertMetaLocation(meta, primary.getRegionName(), serverName100, seqNum100, 100, true); 407 } 408 } 409 410 public static void assertMetaLocation(Table meta, byte[] row, ServerName serverName, 411 long seqNum, int replicaId, boolean checkSeqNum) throws IOException { 412 Get get = new Get(row); 413 Result result = meta.get(get); 414 assertTrue(Bytes.equals( 415 result.getValue(HConstants.CATALOG_FAMILY, MetaTableAccessor.getServerColumn(replicaId)), 416 Bytes.toBytes(serverName.getHostAndPort()))); 417 assertTrue(Bytes.equals( 418 result.getValue(HConstants.CATALOG_FAMILY, MetaTableAccessor.getStartCodeColumn(replicaId)), 419 Bytes.toBytes(serverName.getStartcode()))); 420 if (checkSeqNum) { 421 assertTrue(Bytes.equals( 422 result.getValue(HConstants.CATALOG_FAMILY, MetaTableAccessor.getSeqNumColumn(replicaId)), 423 Bytes.toBytes(seqNum))); 424 } 425 } 426 427 public static void assertEmptyMetaLocation(Table meta, byte[] row, int replicaId) 428 throws IOException { 429 Get get = new Get(row); 430 Result result = meta.get(get); 431 Cell serverCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 432 MetaTableAccessor.getServerColumn(replicaId)); 433 Cell startCodeCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 434 MetaTableAccessor.getStartCodeColumn(replicaId)); 435 assertNotNull(serverCell); 436 assertNotNull(startCodeCell); 437 assertEquals(0, serverCell.getValueLength()); 438 assertEquals(0, startCodeCell.getValueLength()); 439 } 440 441 @Test 442 public void testMetaLocationForRegionReplicasIsAddedAtTableCreation() throws IOException { 443 long regionId = System.currentTimeMillis(); 444 RegionInfo primary = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 445 .setStartKey(HConstants.EMPTY_START_ROW) 446 .setEndKey(HConstants.EMPTY_END_ROW) 447 .setSplit(false) 448 .setRegionId(regionId) 449 .setReplicaId(0) 450 .build(); 451 452 Table meta = MetaTableAccessor.getMetaHTable(connection); 453 try { 454 List<RegionInfo> regionInfos = Lists.newArrayList(primary); 455 MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3); 456 457 assertEmptyMetaLocation(meta, primary.getRegionName(), 1); 458 assertEmptyMetaLocation(meta, primary.getRegionName(), 2); 459 } finally { 460 meta.close(); 461 } 462 } 463 464 @Test 465 public void testMetaLocationForRegionReplicasIsAddedAtRegionSplit() throws IOException { 466 long regionId = System.currentTimeMillis(); 467 ServerName serverName0 = ServerName.valueOf("foo", 60010, random.nextLong()); 468 RegionInfo parent = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 469 .setStartKey(HConstants.EMPTY_START_ROW) 470 .setEndKey(HConstants.EMPTY_END_ROW) 471 .setSplit(false) 472 .setRegionId(regionId) 473 .setReplicaId(0) 474 .build(); 475 476 RegionInfo splitA = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 477 .setStartKey(HConstants.EMPTY_START_ROW) 478 .setEndKey(Bytes.toBytes("a")) 479 .setSplit(false) 480 .setRegionId(regionId + 1) 481 .setReplicaId(0) 482 .build(); 483 RegionInfo splitB = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 484 .setStartKey(Bytes.toBytes("a")) 485 .setEndKey(HConstants.EMPTY_END_ROW) 486 .setSplit(false) 487 .setRegionId(regionId + 1) 488 .setReplicaId(0) 489 .build(); 490 491 try (Table meta = MetaTableAccessor.getMetaHTable(connection)) { 492 List<RegionInfo> regionInfos = Lists.newArrayList(parent); 493 MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3); 494 495 MetaTableAccessor.splitRegion(connection, parent, splitA, splitB, serverName0, 3); 496 497 assertEmptyMetaLocation(meta, splitA.getRegionName(), 1); 498 assertEmptyMetaLocation(meta, splitA.getRegionName(), 2); 499 assertEmptyMetaLocation(meta, splitB.getRegionName(), 1); 500 assertEmptyMetaLocation(meta, splitB.getRegionName(), 2); 501 } 502 } 503 504 @Test 505 public void testMetaLocationForRegionReplicasIsAddedAtRegionMerge() throws IOException { 506 long regionId = System.currentTimeMillis(); 507 ServerName serverName0 = ServerName.valueOf("foo", 60010, random.nextLong()); 508 509 RegionInfo parentA = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 510 .setStartKey(Bytes.toBytes("a")) 511 .setEndKey(HConstants.EMPTY_END_ROW) 512 .setSplit(false) 513 .setRegionId(regionId) 514 .setReplicaId(0) 515 .build(); 516 517 RegionInfo parentB = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 518 .setStartKey(HConstants.EMPTY_START_ROW) 519 .setEndKey(Bytes.toBytes("a")) 520 .setSplit(false) 521 .setRegionId(regionId) 522 .setReplicaId(0) 523 .build(); 524 RegionInfo merged = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 525 .setStartKey(HConstants.EMPTY_START_ROW) 526 .setEndKey(HConstants.EMPTY_END_ROW) 527 .setSplit(false) 528 .setRegionId(regionId + 1) 529 .setReplicaId(0) 530 .build(); 531 532 try (Table meta = MetaTableAccessor.getMetaHTable(connection)) { 533 List<RegionInfo> regionInfos = Lists.newArrayList(parentA, parentB); 534 MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3); 535 536 MetaTableAccessor.mergeRegions(connection, merged, parentA, parentB, serverName0, 3); 537 538 assertEmptyMetaLocation(meta, merged.getRegionName(), 1); 539 assertEmptyMetaLocation(meta, merged.getRegionName(), 2); 540 } 541 } 542 543 @Test 544 public void testMetaScanner() throws Exception { 545 LOG.info("Starting " + name.getMethodName()); 546 547 final TableName tableName = TableName.valueOf(name.getMethodName()); 548 final byte[] FAMILY = Bytes.toBytes("family"); 549 final byte[][] SPLIT_KEYS = 550 new byte[][] { Bytes.toBytes("region_a"), Bytes.toBytes("region_b") }; 551 552 UTIL.createTable(tableName, FAMILY, SPLIT_KEYS); 553 Table table = connection.getTable(tableName); 554 // Make sure all the regions are deployed 555 UTIL.countRows(table); 556 557 MetaTableAccessor.Visitor visitor = 558 mock(MetaTableAccessor.Visitor.class); 559 doReturn(true).when(visitor).visit((Result) anyObject()); 560 561 // Scanning the entire table should give us three rows 562 MetaTableAccessor.scanMetaForTableRegions(connection, visitor, tableName); 563 verify(visitor, times(3)).visit((Result) anyObject()); 564 565 // Scanning the table with a specified empty start row should also 566 // give us three hbase:meta rows 567 reset(visitor); 568 doReturn(true).when(visitor).visit((Result) anyObject()); 569 MetaTableAccessor.scanMeta(connection, visitor, tableName, null, 1000); 570 verify(visitor, times(3)).visit((Result) anyObject()); 571 572 // Scanning the table starting in the middle should give us two rows: 573 // region_a and region_b 574 reset(visitor); 575 doReturn(true).when(visitor).visit((Result) anyObject()); 576 MetaTableAccessor.scanMeta(connection, visitor, tableName, Bytes.toBytes("region_ac"), 1000); 577 verify(visitor, times(2)).visit((Result) anyObject()); 578 579 // Scanning with a limit of 1 should only give us one row 580 reset(visitor); 581 doReturn(true).when(visitor).visit((Result) anyObject()); 582 MetaTableAccessor.scanMeta(connection, visitor, tableName, Bytes.toBytes("region_ac"), 1); 583 verify(visitor, times(1)).visit((Result) anyObject()); 584 table.close(); 585 } 586 587 /** 588 * Tests whether maximum of masters system time versus RSs local system time is used 589 */ 590 @Test 591 public void testMastersSystemTimeIsUsedInUpdateLocations() throws IOException { 592 long regionId = System.currentTimeMillis(); 593 RegionInfo regionInfo = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 594 .setStartKey(HConstants.EMPTY_START_ROW) 595 .setEndKey(HConstants.EMPTY_END_ROW) 596 .setSplit(false) 597 .setRegionId(regionId) 598 .setReplicaId(0) 599 .build(); 600 601 ServerName sn = ServerName.valueOf("bar", 0, 0); 602 try (Table meta = MetaTableAccessor.getMetaHTable(connection)) { 603 List<RegionInfo> regionInfos = Lists.newArrayList(regionInfo); 604 MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 1); 605 606 long masterSystemTime = EnvironmentEdgeManager.currentTime() + 123456789; 607 MetaTableAccessor.updateRegionLocation(connection, regionInfo, sn, 1, masterSystemTime); 608 609 Get get = new Get(regionInfo.getRegionName()); 610 Result result = meta.get(get); 611 Cell serverCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 612 MetaTableAccessor.getServerColumn(0)); 613 Cell startCodeCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 614 MetaTableAccessor.getStartCodeColumn(0)); 615 Cell seqNumCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 616 MetaTableAccessor.getSeqNumColumn(0)); 617 assertNotNull(serverCell); 618 assertNotNull(startCodeCell); 619 assertNotNull(seqNumCell); 620 assertTrue(serverCell.getValueLength() > 0); 621 assertTrue(startCodeCell.getValueLength() > 0); 622 assertTrue(seqNumCell.getValueLength() > 0); 623 assertEquals(masterSystemTime, serverCell.getTimestamp()); 624 assertEquals(masterSystemTime, startCodeCell.getTimestamp()); 625 assertEquals(masterSystemTime, seqNumCell.getTimestamp()); 626 } 627 } 628 629 @Test 630 public void testMastersSystemTimeIsUsedInMergeRegions() throws IOException { 631 long regionId = System.currentTimeMillis(); 632 633 RegionInfo regionInfoA = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 634 .setStartKey(HConstants.EMPTY_START_ROW) 635 .setEndKey(new byte[] {'a'}) 636 .setSplit(false) 637 .setRegionId(regionId) 638 .setReplicaId(0) 639 .build(); 640 641 RegionInfo regionInfoB = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 642 .setStartKey(new byte[] {'a'}) 643 .setEndKey(HConstants.EMPTY_END_ROW) 644 .setSplit(false) 645 .setRegionId(regionId) 646 .setReplicaId(0) 647 .build(); 648 RegionInfo mergedRegionInfo = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 649 .setStartKey(HConstants.EMPTY_START_ROW) 650 .setEndKey(HConstants.EMPTY_END_ROW) 651 .setSplit(false) 652 .setRegionId(regionId) 653 .setReplicaId(0) 654 .build(); 655 656 ServerName sn = ServerName.valueOf("bar", 0, 0); 657 try (Table meta = MetaTableAccessor.getMetaHTable(connection)) { 658 List<RegionInfo> regionInfos = Lists.newArrayList(regionInfoA, regionInfoB); 659 MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 1); 660 661 // write the serverName column with a big current time, but set the masters time as even 662 // bigger. When region merge deletes the rows for regionA and regionB, the serverName columns 663 // should not be seen by the following get 664 long serverNameTime = EnvironmentEdgeManager.currentTime() + 100000000; 665 long masterSystemTime = EnvironmentEdgeManager.currentTime() + 123456789; 666 667 // write the serverName columns 668 MetaTableAccessor.updateRegionLocation(connection, regionInfoA, sn, 1, serverNameTime); 669 670 // assert that we have the serverName column with expected ts 671 Get get = new Get(mergedRegionInfo.getRegionName()); 672 Result result = meta.get(get); 673 Cell serverCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 674 MetaTableAccessor.getServerColumn(0)); 675 assertNotNull(serverCell); 676 assertEquals(serverNameTime, serverCell.getTimestamp()); 677 678 ManualEnvironmentEdge edge = new ManualEnvironmentEdge(); 679 edge.setValue(masterSystemTime); 680 EnvironmentEdgeManager.injectEdge(edge); 681 try { 682 // now merge the regions, effectively deleting the rows for region a and b. 683 MetaTableAccessor.mergeRegions(connection, mergedRegionInfo, regionInfoA, regionInfoB, sn, 684 1); 685 } finally { 686 EnvironmentEdgeManager.reset(); 687 } 688 689 690 result = meta.get(get); 691 serverCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 692 MetaTableAccessor.getServerColumn(0)); 693 Cell startCodeCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 694 MetaTableAccessor.getStartCodeColumn(0)); 695 Cell seqNumCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, 696 MetaTableAccessor.getSeqNumColumn(0)); 697 assertNull(serverCell); 698 assertNull(startCodeCell); 699 assertNull(seqNumCell); 700 } 701 } 702 703 public static class SpyingRpcSchedulerFactory extends SimpleRpcSchedulerFactory { 704 @Override 705 public RpcScheduler create(Configuration conf, PriorityFunction priority, Abortable server) { 706 final RpcScheduler delegate = super.create(conf, priority, server); 707 return new SpyingRpcScheduler(delegate); 708 } 709 } 710 711 public static class SpyingRpcScheduler extends DelegatingRpcScheduler { 712 long numPriorityCalls = 0; 713 714 public SpyingRpcScheduler(RpcScheduler delegate) { 715 super(delegate); 716 } 717 718 @Override 719 public boolean dispatch(CallRunner task) throws IOException, InterruptedException { 720 int priority = task.getRpcCall().getPriority(); 721 722 if (priority > HConstants.QOS_THRESHOLD) { 723 numPriorityCalls++; 724 } 725 return super.dispatch(task); 726 } 727 } 728 729 @Test 730 public void testMetaUpdatesGoToPriorityQueue() throws Exception { 731 // This test has to be end-to-end, and do the verification from the server side 732 Configuration c = UTIL.getConfiguration(); 733 734 c.set(RSRpcServices.REGION_SERVER_RPC_SCHEDULER_FACTORY_CLASS, 735 SpyingRpcSchedulerFactory.class.getName()); 736 737 // restart so that new config takes place 738 afterClass(); 739 beforeClass(); 740 741 final TableName tableName = TableName.valueOf(name.getMethodName()); 742 try (Admin admin = connection.getAdmin(); 743 RegionLocator rl = connection.getRegionLocator(tableName)) { 744 745 // create a table and prepare for a manual split 746 UTIL.createTable(tableName, "cf1"); 747 748 HRegionLocation loc = rl.getAllRegionLocations().get(0); 749 RegionInfo parent = loc.getRegionInfo(); 750 long rid = 1000; 751 byte[] splitKey = Bytes.toBytes("a"); 752 RegionInfo splitA = RegionInfoBuilder.newBuilder(parent.getTable()) 753 .setStartKey(parent.getStartKey()) 754 .setEndKey(splitKey) 755 .setSplit(false) 756 .setRegionId(rid) 757 .build(); 758 RegionInfo splitB = RegionInfoBuilder.newBuilder(parent.getTable()) 759 .setStartKey(splitKey) 760 .setEndKey(parent.getEndKey()) 761 .setSplit(false) 762 .setRegionId(rid) 763 .build(); 764 765 // find the meta server 766 MiniHBaseCluster cluster = UTIL.getMiniHBaseCluster(); 767 int rsIndex = cluster.getServerWithMeta(); 768 HRegionServer rs; 769 if (rsIndex >= 0) { 770 rs = cluster.getRegionServer(rsIndex); 771 } else { 772 // it is in master 773 rs = cluster.getMaster(); 774 } 775 SpyingRpcScheduler scheduler = (SpyingRpcScheduler) rs.getRpcServer().getScheduler(); 776 long prevCalls = scheduler.numPriorityCalls; 777 MetaTableAccessor.splitRegion(connection, parent, splitA, splitB, loc.getServerName(), 1); 778 779 assertTrue(prevCalls < scheduler.numPriorityCalls); 780 } 781 } 782 783 @Test 784 public void testEmptyMetaDaughterLocationDuringSplit() throws IOException { 785 long regionId = System.currentTimeMillis(); 786 ServerName serverName0 = ServerName.valueOf("foo", 60010, random.nextLong()); 787 RegionInfo parent = RegionInfoBuilder.newBuilder(TableName.valueOf("table_foo")) 788 .setStartKey(HConstants.EMPTY_START_ROW) 789 .setEndKey(HConstants.EMPTY_END_ROW) 790 .setSplit(false) 791 .setRegionId(regionId) 792 .setReplicaId(0) 793 .build(); 794 RegionInfo splitA = RegionInfoBuilder.newBuilder(TableName.valueOf("table_foo")) 795 .setStartKey(HConstants.EMPTY_START_ROW) 796 .setEndKey(Bytes.toBytes("a")) 797 .setSplit(false) 798 .setRegionId(regionId + 1) 799 .setReplicaId(0) 800 .build(); 801 RegionInfo splitB = RegionInfoBuilder.newBuilder(TableName.valueOf("table_foo")) 802 .setStartKey(Bytes.toBytes("a")) 803 .setEndKey(HConstants.EMPTY_END_ROW) 804 .setSplit(false) 805 .setRegionId(regionId + 1) 806 .setReplicaId(0) 807 .build(); 808 809 Table meta = MetaTableAccessor.getMetaHTable(connection); 810 try { 811 List<RegionInfo> regionInfos = Lists.newArrayList(parent); 812 MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3); 813 814 MetaTableAccessor.splitRegion(connection, parent, splitA, splitB, serverName0, 3); 815 Get get1 = new Get(splitA.getRegionName()); 816 Result resultA = meta.get(get1); 817 Cell serverCellA = resultA.getColumnLatestCell(HConstants.CATALOG_FAMILY, 818 MetaTableAccessor.getServerColumn(splitA.getReplicaId())); 819 Cell startCodeCellA = resultA.getColumnLatestCell(HConstants.CATALOG_FAMILY, 820 MetaTableAccessor.getStartCodeColumn(splitA.getReplicaId())); 821 assertNull(serverCellA); 822 assertNull(startCodeCellA); 823 824 Get get2 = new Get(splitA.getRegionName()); 825 Result resultB = meta.get(get2); 826 Cell serverCellB = resultB.getColumnLatestCell(HConstants.CATALOG_FAMILY, 827 MetaTableAccessor.getServerColumn(splitB.getReplicaId())); 828 Cell startCodeCellB = resultB.getColumnLatestCell(HConstants.CATALOG_FAMILY, 829 MetaTableAccessor.getStartCodeColumn(splitB.getReplicaId())); 830 assertNull(serverCellB); 831 assertNull(startCodeCellB); 832 } finally { 833 if (meta != null) { 834 meta.close(); 835 } 836 } 837 } 838} 839