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