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