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