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