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.regionserver; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNotEquals; 023import static org.junit.Assert.assertNotNull; 024import static org.junit.Assert.assertNotSame; 025import static org.junit.Assert.assertNull; 026import static org.junit.Assert.assertTrue; 027import static org.junit.Assert.fail; 028 029import java.io.IOException; 030import java.lang.reflect.Field; 031import java.util.ArrayList; 032import java.util.Collection; 033import java.util.List; 034import java.util.Map; 035import java.util.Optional; 036import java.util.concurrent.CountDownLatch; 037import java.util.concurrent.ExecutionException; 038import java.util.concurrent.TimeUnit; 039import java.util.concurrent.TimeoutException; 040import java.util.concurrent.atomic.AtomicBoolean; 041import org.apache.commons.io.IOUtils; 042import org.apache.hadoop.conf.Configuration; 043import org.apache.hadoop.fs.FileSystem; 044import org.apache.hadoop.fs.Path; 045import org.apache.hadoop.hbase.Coprocessor; 046import org.apache.hadoop.hbase.CoprocessorEnvironment; 047import org.apache.hadoop.hbase.DoNotRetryIOException; 048import org.apache.hadoop.hbase.HBaseClassTestRule; 049import org.apache.hadoop.hbase.HBaseTestingUtility; 050import org.apache.hadoop.hbase.HConstants; 051import org.apache.hadoop.hbase.HTableDescriptor; 052import org.apache.hadoop.hbase.MasterNotRunningException; 053import org.apache.hadoop.hbase.MiniHBaseCluster; 054import org.apache.hadoop.hbase.ServerName; 055import org.apache.hadoop.hbase.StartMiniClusterOption; 056import org.apache.hadoop.hbase.TableName; 057import org.apache.hadoop.hbase.UnknownRegionException; 058import org.apache.hadoop.hbase.ZooKeeperConnectionException; 059import org.apache.hadoop.hbase.client.Admin; 060import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 061import org.apache.hadoop.hbase.client.Consistency; 062import org.apache.hadoop.hbase.client.Delete; 063import org.apache.hadoop.hbase.client.DoNotRetryRegionException; 064import org.apache.hadoop.hbase.client.Get; 065import org.apache.hadoop.hbase.client.Mutation; 066import org.apache.hadoop.hbase.client.Put; 067import org.apache.hadoop.hbase.client.RegionInfo; 068import org.apache.hadoop.hbase.client.Result; 069import org.apache.hadoop.hbase.client.ResultScanner; 070import org.apache.hadoop.hbase.client.Scan; 071import org.apache.hadoop.hbase.client.Table; 072import org.apache.hadoop.hbase.client.TableDescriptor; 073import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 074import org.apache.hadoop.hbase.client.TestReplicasClient.SlowMeCopro; 075import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor; 076import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; 077import org.apache.hadoop.hbase.coprocessor.MasterObserver; 078import org.apache.hadoop.hbase.coprocessor.ObserverContext; 079import org.apache.hadoop.hbase.io.Reference; 080import org.apache.hadoop.hbase.master.HMaster; 081import org.apache.hadoop.hbase.master.LoadBalancer; 082import org.apache.hadoop.hbase.master.MasterRpcServices; 083import org.apache.hadoop.hbase.master.RegionState; 084import org.apache.hadoop.hbase.master.RegionState.State; 085import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 086import org.apache.hadoop.hbase.master.assignment.AssignmentTestingUtil; 087import org.apache.hadoop.hbase.master.assignment.RegionStateNode; 088import org.apache.hadoop.hbase.master.assignment.RegionStates; 089import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 090import org.apache.hadoop.hbase.regionserver.compactions.CompactionContext; 091import org.apache.hadoop.hbase.regionserver.compactions.CompactionLifeCycleTracker; 092import org.apache.hadoop.hbase.regionserver.compactions.CompactionProgress; 093import org.apache.hadoop.hbase.regionserver.throttle.NoLimitThroughputController; 094import org.apache.hadoop.hbase.testclassification.LargeTests; 095import org.apache.hadoop.hbase.testclassification.RegionServerTests; 096import org.apache.hadoop.hbase.util.Bytes; 097import org.apache.hadoop.hbase.util.CommonFSUtils; 098import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 099import org.apache.hadoop.hbase.util.FSUtils; 100import org.apache.hadoop.hbase.util.HBaseFsck; 101import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; 102import org.apache.hadoop.hbase.util.Threads; 103import org.apache.zookeeper.KeeperException; 104import org.apache.zookeeper.KeeperException.NodeExistsException; 105import org.junit.After; 106import org.junit.AfterClass; 107import org.junit.Assert; 108import org.junit.Before; 109import org.junit.BeforeClass; 110import org.junit.ClassRule; 111import org.junit.Rule; 112import org.junit.Test; 113import org.junit.experimental.categories.Category; 114import org.junit.rules.TestName; 115import org.mockito.Mockito; 116import org.slf4j.Logger; 117import org.slf4j.LoggerFactory; 118 119import org.apache.hbase.thirdparty.com.google.protobuf.RpcController; 120import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; 121 122import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 123import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionStateTransition.TransitionCode; 124import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.ReportRegionStateTransitionRequest; 125import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.ReportRegionStateTransitionResponse; 126 127/** 128 * The below tests are testing split region against a running cluster 129 */ 130@Category({RegionServerTests.class, LargeTests.class}) 131public class TestSplitTransactionOnCluster { 132 133 @ClassRule 134 public static final HBaseClassTestRule CLASS_RULE = 135 HBaseClassTestRule.forClass(TestSplitTransactionOnCluster.class); 136 137 private static final Logger LOG = LoggerFactory.getLogger(TestSplitTransactionOnCluster.class); 138 private Admin admin = null; 139 private MiniHBaseCluster cluster = null; 140 private static final int NB_SERVERS = 3; 141 142 static final HBaseTestingUtility TESTING_UTIL = 143 new HBaseTestingUtility(); 144 145 @Rule 146 public TestName name = new TestName(); 147 148 @BeforeClass public static void before() throws Exception { 149 TESTING_UTIL.getConfiguration().setInt(HConstants.HBASE_BALANCER_PERIOD, 60000); 150 StartMiniClusterOption option = StartMiniClusterOption.builder() 151 .masterClass(MyMaster.class).numRegionServers(NB_SERVERS). 152 numDataNodes(NB_SERVERS).build(); 153 TESTING_UTIL.startMiniCluster(option); 154 } 155 156 @AfterClass public static void after() throws Exception { 157 TESTING_UTIL.shutdownMiniCluster(); 158 } 159 160 @Before public void setup() throws IOException { 161 TESTING_UTIL.ensureSomeNonStoppedRegionServersAvailable(NB_SERVERS); 162 this.admin = TESTING_UTIL.getAdmin(); 163 this.cluster = TESTING_UTIL.getMiniHBaseCluster(); 164 } 165 166 @After 167 public void tearDown() throws Exception { 168 this.admin.close(); 169 for (TableDescriptor htd: this.admin.listTableDescriptors()) { 170 LOG.info("Tear down, remove table=" + htd.getTableName()); 171 TESTING_UTIL.deleteTable(htd.getTableName()); 172 } 173 } 174 175 private RegionInfo getAndCheckSingleTableRegion(final List<HRegion> regions) 176 throws IOException, InterruptedException { 177 assertEquals(1, regions.size()); 178 RegionInfo hri = regions.get(0).getRegionInfo(); 179 AssignmentTestingUtil.waitForAssignment(cluster.getMaster().getAssignmentManager(), hri); 180 return hri; 181 } 182 183 private void requestSplitRegion( 184 final HRegionServer rsServer, 185 final Region region, 186 final byte[] midKey) throws IOException { 187 long procId = cluster.getMaster().splitRegion(region.getRegionInfo(), midKey, 0, 0); 188 // wait for the split to complete or get interrupted. If the split completes successfully, 189 // the procedure will return true; if the split fails, the procedure would throw exception. 190 ProcedureTestingUtility.waitProcedure(cluster.getMaster().getMasterProcedureExecutor(), procId); 191 } 192 193 @Test 194 public void testRITStateForRollback() throws Exception { 195 final TableName tableName = TableName.valueOf(name.getMethodName()); 196 final HMaster master = cluster.getMaster(); 197 try { 198 // Create table then get the single region for our new table. 199 Table t = createTableAndWait(tableName, Bytes.toBytes("cf")); 200 final List<HRegion> regions = cluster.getRegions(tableName); 201 final RegionInfo hri = getAndCheckSingleTableRegion(regions); 202 insertData(tableName, admin, t); 203 t.close(); 204 205 // Turn off balancer so it doesn't cut in and mess up our placements. 206 this.admin.balancerSwitch(false, true); 207 // Turn off the meta scanner so it don't remove parent on us. 208 master.setCatalogJanitorEnabled(false); 209 210 // find a splittable region 211 final HRegion region = findSplittableRegion(regions); 212 assertTrue("not able to find a splittable region", region != null); 213 214 // install master co-processor to fail splits 215 master.getMasterCoprocessorHost().load( 216 FailingSplitMasterObserver.class, 217 Coprocessor.PRIORITY_USER, 218 master.getConfiguration()); 219 220 // split async 221 this.admin.splitRegionAsync(region.getRegionInfo().getRegionName(), new byte[] { 42 }); 222 223 // we have to wait until the SPLITTING state is seen by the master 224 FailingSplitMasterObserver observer = 225 master.getMasterCoprocessorHost().findCoprocessor(FailingSplitMasterObserver.class); 226 assertNotNull(observer); 227 observer.latch.await(); 228 229 LOG.info("Waiting for region to come out of RIT"); 230 while (!cluster.getMaster().getAssignmentManager().getRegionStates().isRegionOnline(hri)) { 231 Threads.sleep(100); 232 } 233 assertTrue(cluster.getMaster().getAssignmentManager().getRegionStates().isRegionOnline(hri)); 234 } finally { 235 admin.balancerSwitch(true, false); 236 master.setCatalogJanitorEnabled(true); 237 abortAndWaitForMaster(); 238 TESTING_UTIL.deleteTable(tableName); 239 } 240 } 241 242 @Test 243 public void testSplitFailedCompactionAndSplit() throws Exception { 244 final TableName tableName = TableName.valueOf(name.getMethodName()); 245 // Create table then get the single region for our new table. 246 byte[] cf = Bytes.toBytes("cf"); 247 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 248 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf)).build(); 249 admin.createTable(htd); 250 251 for (int i = 0; cluster.getRegions(tableName).isEmpty() && i < 100; i++) { 252 Thread.sleep(100); 253 } 254 assertEquals(1, cluster.getRegions(tableName).size()); 255 256 HRegion region = cluster.getRegions(tableName).get(0); 257 HStore store = region.getStore(cf); 258 int regionServerIndex = cluster.getServerWith(region.getRegionInfo().getRegionName()); 259 HRegionServer regionServer = cluster.getRegionServer(regionServerIndex); 260 261 Table t = TESTING_UTIL.getConnection().getTable(tableName); 262 // insert data 263 insertData(tableName, admin, t); 264 insertData(tableName, admin, t); 265 266 int fileNum = store.getStorefiles().size(); 267 // 0, Compaction Request 268 store.triggerMajorCompaction(); 269 Optional<CompactionContext> cc = store.requestCompaction(); 270 assertTrue(cc.isPresent()); 271 // 1, A timeout split 272 // 1.1 close region 273 assertEquals(2, region.close(false).get(cf).size()); 274 // 1.2 rollback and Region initialize again 275 region.initialize(); 276 277 // 2, Run Compaction cc 278 assertFalse(region.compact(cc.get(), store, NoLimitThroughputController.INSTANCE)); 279 assertTrue(fileNum > store.getStorefiles().size()); 280 281 // 3, Split 282 requestSplitRegion(regionServer, region, Bytes.toBytes("row3")); 283 assertEquals(2, cluster.getRegions(tableName).size()); 284 } 285 286 @Test 287 public void testSplitCompactWithPriority() throws Exception { 288 final TableName tableName = TableName.valueOf(name.getMethodName()); 289 // Create table then get the single region for our new table. 290 byte[] cf = Bytes.toBytes("cf"); 291 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 292 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf)).build(); 293 admin.createTable(htd); 294 295 assertNotEquals("Unable to retrieve regions of the table", -1, 296 TESTING_UTIL.waitFor(10000, () -> cluster.getRegions(tableName).size() == 1)); 297 298 HRegion region = cluster.getRegions(tableName).get(0); 299 HStore store = region.getStore(cf); 300 int regionServerIndex = cluster.getServerWith(region.getRegionInfo().getRegionName()); 301 HRegionServer regionServer = cluster.getRegionServer(regionServerIndex); 302 303 Table table = TESTING_UTIL.getConnection().getTable(tableName); 304 // insert data 305 insertData(tableName, admin, table); 306 insertData(tableName, admin, table, 20); 307 insertData(tableName, admin, table, 40); 308 309 // Compaction Request 310 store.triggerMajorCompaction(); 311 Optional<CompactionContext> compactionContext = store.requestCompaction(); 312 assertTrue(compactionContext.isPresent()); 313 assertFalse(compactionContext.get().getRequest().isAfterSplit()); 314 assertEquals(compactionContext.get().getRequest().getPriority(), 13); 315 316 // Split 317 long procId = 318 cluster.getMaster().splitRegion(region.getRegionInfo(), Bytes.toBytes("row4"), 0, 0); 319 320 // wait for the split to complete or get interrupted. If the split completes successfully, 321 // the procedure will return true; if the split fails, the procedure would throw exception. 322 ProcedureTestingUtility.waitProcedure(cluster.getMaster().getMasterProcedureExecutor(), 323 procId); 324 Thread.sleep(3000); 325 assertNotEquals("Table is not split properly?", -1, 326 TESTING_UTIL.waitFor(3000, 327 () -> cluster.getRegions(tableName).size() == 2)); 328 // we have 2 daughter regions 329 HRegion hRegion1 = cluster.getRegions(tableName).get(0); 330 HRegion hRegion2 = cluster.getRegions(tableName).get(1); 331 HStore hStore1 = hRegion1.getStore(cf); 332 HStore hStore2 = hRegion2.getStore(cf); 333 334 // For hStore1 && hStore2, set mock reference to one of the storeFiles 335 StoreFileInfo storeFileInfo1 = new ArrayList<>(hStore1.getStorefiles()).get(0).getFileInfo(); 336 StoreFileInfo storeFileInfo2 = new ArrayList<>(hStore2.getStorefiles()).get(0).getFileInfo(); 337 Field field = StoreFileInfo.class.getDeclaredField("reference"); 338 field.setAccessible(true); 339 field.set(storeFileInfo1, Mockito.mock(Reference.class)); 340 field.set(storeFileInfo2, Mockito.mock(Reference.class)); 341 hStore1.triggerMajorCompaction(); 342 hStore2.triggerMajorCompaction(); 343 344 compactionContext = hStore1.requestCompaction(); 345 assertTrue(compactionContext.isPresent()); 346 // since we set mock reference to one of the storeFiles, we will get isAfterSplit=true && 347 // highest priority for hStore1's compactionContext 348 assertTrue(compactionContext.get().getRequest().isAfterSplit()); 349 assertEquals(compactionContext.get().getRequest().getPriority(), Integer.MIN_VALUE + 1000); 350 351 compactionContext = 352 hStore2.requestCompaction(Integer.MIN_VALUE + 10, CompactionLifeCycleTracker.DUMMY, null); 353 assertTrue(compactionContext.isPresent()); 354 // compaction request contains higher priority than default priority of daughter region 355 // compaction (Integer.MIN_VALUE + 1000), hence we are expecting request priority to 356 // be accepted. 357 assertTrue(compactionContext.get().getRequest().isAfterSplit()); 358 assertEquals(compactionContext.get().getRequest().getPriority(), Integer.MIN_VALUE + 10); 359 admin.disableTable(tableName); 360 admin.deleteTable(tableName); 361 } 362 363 public static class FailingSplitMasterObserver implements MasterCoprocessor, MasterObserver { 364 volatile CountDownLatch latch; 365 366 @Override 367 public void start(CoprocessorEnvironment e) throws IOException { 368 latch = new CountDownLatch(1); 369 } 370 371 @Override 372 public Optional<MasterObserver> getMasterObserver() { 373 return Optional.of(this); 374 } 375 376 @Override 377 public void preSplitRegionBeforeMETAAction( 378 final ObserverContext<MasterCoprocessorEnvironment> ctx, 379 final byte[] splitKey, 380 final List<Mutation> metaEntries) throws IOException { 381 latch.countDown(); 382 throw new IOException("Causing rollback of region split"); 383 } 384 } 385 386 @Test 387 public void testSplitRollbackOnRegionClosing() throws Exception { 388 final TableName tableName = TableName.valueOf(name.getMethodName()); 389 390 // Create table then get the single region for our new table. 391 Table t = createTableAndWait(tableName, HConstants.CATALOG_FAMILY); 392 List<HRegion> regions = cluster.getRegions(tableName); 393 RegionInfo hri = getAndCheckSingleTableRegion(regions); 394 395 int tableRegionIndex = ensureTableRegionNotOnSameServerAsMeta(admin, hri); 396 397 RegionStates regionStates = cluster.getMaster().getAssignmentManager().getRegionStates(); 398 399 // Turn off balancer so it doesn't cut in and mess up our placements. 400 this.admin.balancerSwitch(false, true); 401 // Turn off the meta scanner so it don't remove parent on us. 402 cluster.getMaster().setCatalogJanitorEnabled(false); 403 try { 404 // Add a bit of load up into the table so splittable. 405 TESTING_UTIL.loadTable(t, HConstants.CATALOG_FAMILY, false); 406 // Get region pre-split. 407 HRegionServer server = cluster.getRegionServer(tableRegionIndex); 408 printOutRegions(server, "Initial regions: "); 409 int regionCount = cluster.getRegions(hri.getTable()).size(); 410 regionStates.updateRegionState(hri, RegionState.State.CLOSING); 411 412 // Now try splitting.... should fail. And each should successfully 413 // rollback. 414 // We don't roll back here anymore. Instead we fail-fast on construction of the 415 // split transaction. Catch the exception instead. 416 try { 417 this.admin.splitRegionAsync(hri.getRegionName()); 418 fail(); 419 } catch (DoNotRetryRegionException e) { 420 // Expected 421 } 422 // Wait around a while and assert count of regions remains constant. 423 for (int i = 0; i < 10; i++) { 424 Thread.sleep(100); 425 assertEquals(regionCount, cluster.getRegions(hri.getTable()).size()); 426 } 427 regionStates.updateRegionState(hri, State.OPEN); 428 // Now try splitting and it should work. 429 admin.splitRegionAsync(hri.getRegionName()).get(2, TimeUnit.MINUTES); 430 // Get daughters 431 checkAndGetDaughters(tableName); 432 // OK, so split happened after we cleared the blocking node. 433 } finally { 434 admin.balancerSwitch(true, false); 435 cluster.getMaster().setCatalogJanitorEnabled(true); 436 t.close(); 437 } 438 } 439 440 /** 441 * Test that if daughter split on us, we won't do the shutdown handler fixup just because we can't 442 * find the immediate daughter of an offlined parent. 443 */ 444 @Test 445 public void testShutdownFixupWhenDaughterHasSplit() throws Exception { 446 final TableName tableName = TableName.valueOf(name.getMethodName()); 447 448 // Create table then get the single region for our new table. 449 Table t = createTableAndWait(tableName, HConstants.CATALOG_FAMILY); List<HRegion> regions = 450 cluster.getRegions(tableName); RegionInfo hri = getAndCheckSingleTableRegion(regions); 451 int tableRegionIndex = ensureTableRegionNotOnSameServerAsMeta(admin, hri); 452 453 // Turn off balancer so it doesn't cut in and mess up our placements. 454 this.admin.balancerSwitch(false, true); 455 // Turn off the meta scanner so it don't remove parent on us. 456 cluster.getMaster().setCatalogJanitorEnabled(false); 457 try { 458 // Add a bit of load up into the table so splittable. 459 TESTING_UTIL.loadTable(t, HConstants.CATALOG_FAMILY); 460 // Get region pre-split. 461 HRegionServer server = cluster.getRegionServer(tableRegionIndex); 462 printOutRegions(server, "Initial regions: "); 463 // Now split. 464 admin.splitRegionAsync(hri.getRegionName()).get(2, TimeUnit.MINUTES); 465 // Get daughters 466 List<HRegion> daughters = checkAndGetDaughters(tableName); 467 // Now split one of the daughters. 468 HRegion daughterRegion = daughters.get(0); 469 RegionInfo daughter = daughterRegion.getRegionInfo(); 470 LOG.info("Daughter we are going to split: " + daughter); 471 clearReferences(daughterRegion); 472 LOG.info("Finished {} references={}", daughterRegion, daughterRegion.hasReferences()); 473 admin.splitRegionAsync(daughter.getRegionName()).get(2, TimeUnit.MINUTES); 474 // Get list of daughters 475 daughters = cluster.getRegions(tableName); 476 for (HRegion d: daughters) { 477 LOG.info("Regions before crash: " + d); 478 } 479 // Now crash the server 480 cluster.abortRegionServer(tableRegionIndex); 481 waitUntilRegionServerDead(); 482 awaitDaughters(tableName, daughters.size()); 483 // Assert daughters are online and ONLY the original daughters -- that 484 // fixup didn't insert one during server shutdown recover. 485 regions = cluster.getRegions(tableName); 486 for (HRegion d: daughters) { 487 LOG.info("Regions after crash: " + d); 488 } 489 if (daughters.size() != regions.size()) { 490 LOG.info("Daughters=" + daughters.size() + ", regions=" + regions.size()); 491 } 492 assertEquals(daughters.size(), regions.size()); 493 for (HRegion r: regions) { 494 LOG.info("Regions post crash " + r + ", contains=" + daughters.contains(r)); 495 assertTrue("Missing region post crash " + r, daughters.contains(r)); 496 } 497 } finally { 498 LOG.info("EXITING"); 499 admin.balancerSwitch(true, false); 500 cluster.getMaster().setCatalogJanitorEnabled(true); 501 t.close(); 502 } 503 } 504 505 private void clearReferences(HRegion region) throws IOException { 506 // Presumption. 507 assertEquals(1, region.getStores().size()); 508 HStore store = region.getStores().get(0); 509 while (store.hasReferences()) { 510 // Wait on any current compaction to complete first. 511 CompactionProgress progress = store.getCompactionProgress(); 512 if (progress != null && progress.getProgressPct() < 1.0f) { 513 while (progress.getProgressPct() < 1.0f) { 514 LOG.info("Waiting, progress={}", progress.getProgressPct()); 515 Threads.sleep(1000); 516 } 517 } else { 518 // Run new compaction. Shoudn't be any others running. 519 region.compact(true); 520 } 521 store.closeAndArchiveCompactedFiles(); 522 } 523 } 524 525 @Test 526 public void testSplitShouldNotThrowNPEEvenARegionHasEmptySplitFiles() throws Exception { 527 TableName userTableName = TableName.valueOf(name.getMethodName()); 528 TableDescriptor htd = TableDescriptorBuilder.newBuilder(userTableName) 529 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("col")).build(); 530 admin.createTable(htd); 531 Table table = TESTING_UTIL.getConnection().getTable(userTableName); 532 try { 533 for (int i = 0; i <= 5; i++) { 534 String row = "row" + i; 535 Put p = new Put(row.getBytes()); 536 String val = "Val" + i; 537 p.addColumn("col".getBytes(), "ql".getBytes(), val.getBytes()); 538 table.put(p); 539 admin.flush(userTableName); 540 Delete d = new Delete(row.getBytes()); 541 // Do a normal delete 542 table.delete(d); 543 admin.flush(userTableName); 544 } 545 admin.majorCompact(userTableName); 546 List<RegionInfo> regionsOfTable = 547 cluster.getMaster().getAssignmentManager().getRegionStates() 548 .getRegionsOfTable(userTableName); 549 assertEquals(1, regionsOfTable.size()); 550 RegionInfo hRegionInfo = regionsOfTable.get(0); 551 Put p = new Put("row6".getBytes()); 552 p.addColumn("col".getBytes(), "ql".getBytes(), "val".getBytes()); 553 table.put(p); 554 p = new Put("row7".getBytes()); 555 p.addColumn("col".getBytes(), "ql".getBytes(), "val".getBytes()); 556 table.put(p); 557 p = new Put("row8".getBytes()); 558 p.addColumn("col".getBytes(), "ql".getBytes(), "val".getBytes()); 559 table.put(p); 560 admin.flush(userTableName); 561 admin.splitRegionAsync(hRegionInfo.getRegionName(), "row7".getBytes()); 562 regionsOfTable = cluster.getMaster() 563 .getAssignmentManager().getRegionStates() 564 .getRegionsOfTable(userTableName); 565 566 while (regionsOfTable.size() != 2) { 567 Thread.sleep(1000); 568 regionsOfTable = cluster.getMaster() 569 .getAssignmentManager().getRegionStates() 570 .getRegionsOfTable(userTableName); 571 LOG.debug("waiting 2 regions to be available, got " + regionsOfTable.size() + 572 ": " + regionsOfTable); 573 574 } 575 Assert.assertEquals(2, regionsOfTable.size()); 576 577 Scan s = new Scan(); 578 ResultScanner scanner = table.getScanner(s); 579 int mainTableCount = 0; 580 for (Result rr = scanner.next(); rr != null; rr = scanner.next()) { 581 mainTableCount++; 582 } 583 Assert.assertEquals(3, mainTableCount); 584 } finally { 585 table.close(); 586 } 587 } 588 589 /** 590 * Verifies HBASE-5806. Here the case is that splitting is completed but before the CJ could 591 * remove the parent region the master is killed and restarted. 592 */ 593 @Test 594 public void testMasterRestartAtRegionSplitPendingCatalogJanitor() 595 throws IOException, InterruptedException, NodeExistsException, KeeperException, 596 ServiceException, ExecutionException, TimeoutException { 597 final TableName tableName = TableName.valueOf(name.getMethodName()); 598 // Create table then get the single region for our new table. 599 try (Table t = createTableAndWait(tableName, HConstants.CATALOG_FAMILY)) { 600 List<HRegion> regions = cluster.getRegions(tableName); 601 RegionInfo hri = getAndCheckSingleTableRegion(regions); 602 603 int tableRegionIndex = ensureTableRegionNotOnSameServerAsMeta(admin, hri); 604 605 // Turn off balancer so it doesn't cut in and mess up our placements. 606 this.admin.balancerSwitch(false, true); 607 // Turn off the meta scanner so it don't remove parent on us. 608 cluster.getMaster().setCatalogJanitorEnabled(false); 609 // Add a bit of load up into the table so splittable. 610 TESTING_UTIL.loadTable(t, HConstants.CATALOG_FAMILY, false); 611 // Get region pre-split. 612 HRegionServer server = cluster.getRegionServer(tableRegionIndex); 613 printOutRegions(server, "Initial regions: "); 614 // Call split. 615 this.admin.splitRegionAsync(hri.getRegionName()).get(2, TimeUnit.MINUTES); 616 List<HRegion> daughters = checkAndGetDaughters(tableName); 617 618 // Before cleanup, get a new master. 619 HMaster master = abortAndWaitForMaster(); 620 // Now call compact on the daughters and clean up any references. 621 for (HRegion daughter : daughters) { 622 clearReferences(daughter); 623 assertFalse(daughter.hasReferences()); 624 } 625 // BUT calling compact on the daughters is not enough. The CatalogJanitor looks 626 // in the filesystem, and the filesystem content is not same as what the Region 627 // is reading from. Compacted-away files are picked up later by the compacted 628 // file discharger process. It runs infrequently. Make it run so CatalogJanitor 629 // doens't find any references. 630 for (RegionServerThread rst : cluster.getRegionServerThreads()) { 631 boolean oldSetting = rst.getRegionServer().compactedFileDischarger.setUseExecutor(false); 632 rst.getRegionServer().compactedFileDischarger.run(); 633 rst.getRegionServer().compactedFileDischarger.setUseExecutor(oldSetting); 634 } 635 cluster.getMaster().setCatalogJanitorEnabled(true); 636 ProcedureTestingUtility.waitAllProcedures(cluster.getMaster().getMasterProcedureExecutor()); 637 LOG.info("Starting run of CatalogJanitor"); 638 cluster.getMaster().getCatalogJanitor().run(); 639 ProcedureTestingUtility.waitAllProcedures(cluster.getMaster().getMasterProcedureExecutor()); 640 RegionStates regionStates = master.getAssignmentManager().getRegionStates(); 641 ServerName regionServerOfRegion = regionStates.getRegionServerOfRegion(hri); 642 assertEquals(null, regionServerOfRegion); 643 } finally { 644 TESTING_UTIL.getAdmin().balancerSwitch(true, false); 645 cluster.getMaster().setCatalogJanitorEnabled(true); 646 } 647 } 648 649 @Test 650 public void testSplitWithRegionReplicas() throws Exception { 651 final TableName tableName = TableName.valueOf(name.getMethodName()); 652 HTableDescriptor htd = TESTING_UTIL.createTableDescriptor(name.getMethodName()); 653 htd.setRegionReplication(2); 654 htd.addCoprocessor(SlowMeCopro.class.getName()); 655 // Create table then get the single region for our new table. 656 Table t = TESTING_UTIL.createTable(htd, new byte[][]{Bytes.toBytes("cf")}, null); 657 List<HRegion> oldRegions; 658 do { 659 oldRegions = cluster.getRegions(tableName); 660 Thread.sleep(10); 661 } while (oldRegions.size() != 2); 662 for (HRegion h : oldRegions) LOG.debug("OLDREGION " + h.getRegionInfo()); 663 try { 664 int regionServerIndex = cluster.getServerWith(oldRegions.get(0).getRegionInfo() 665 .getRegionName()); 666 HRegionServer regionServer = cluster.getRegionServer(regionServerIndex); 667 insertData(tableName, admin, t); 668 // Turn off balancer so it doesn't cut in and mess up our placements. 669 admin.balancerSwitch(false, true); 670 // Turn off the meta scanner so it don't remove parent on us. 671 cluster.getMaster().setCatalogJanitorEnabled(false); 672 boolean tableExists = TESTING_UTIL.getAdmin().tableExists(tableName); 673 assertEquals("The specified table should be present.", true, tableExists); 674 final HRegion region = findSplittableRegion(oldRegions); 675 regionServerIndex = cluster.getServerWith(region.getRegionInfo().getRegionName()); 676 regionServer = cluster.getRegionServer(regionServerIndex); 677 assertTrue("not able to find a splittable region", region != null); 678 try { 679 requestSplitRegion(regionServer, region, Bytes.toBytes("row2")); 680 } catch (IOException e) { 681 e.printStackTrace(); 682 fail("Split execution should have succeeded with no exceptions thrown " + e); 683 } 684 //TESTING_UTIL.waitUntilAllRegionsAssigned(tableName); 685 List<HRegion> newRegions; 686 do { 687 newRegions = cluster.getRegions(tableName); 688 for (HRegion h : newRegions) LOG.debug("NEWREGION " + h.getRegionInfo()); 689 Thread.sleep(1000); 690 } while ((newRegions.contains(oldRegions.get(0)) || newRegions.contains(oldRegions.get(1))) 691 || newRegions.size() != 4); 692 tableExists = TESTING_UTIL.getAdmin().tableExists(tableName); 693 assertEquals("The specified table should be present.", true, tableExists); 694 // exists works on stale and we see the put after the flush 695 byte[] b1 = "row1".getBytes(); 696 Get g = new Get(b1); 697 g.setConsistency(Consistency.STRONG); 698 // The following GET will make a trip to the meta to get the new location of the 1st daughter 699 // In the process it will also get the location of the replica of the daughter (initially 700 // pointing to the parent's replica) 701 Result r = t.get(g); 702 Assert.assertFalse(r.isStale()); 703 LOG.info("exists stale after flush done"); 704 705 SlowMeCopro.getPrimaryCdl().set(new CountDownLatch(1)); 706 g = new Get(b1); 707 g.setConsistency(Consistency.TIMELINE); 708 // This will succeed because in the previous GET we get the location of the replica 709 r = t.get(g); 710 Assert.assertTrue(r.isStale()); 711 SlowMeCopro.getPrimaryCdl().get().countDown(); 712 } finally { 713 SlowMeCopro.getPrimaryCdl().get().countDown(); 714 admin.balancerSwitch(true, false); 715 cluster.getMaster().setCatalogJanitorEnabled(true); 716 t.close(); 717 } 718 } 719 720 private void insertData(final TableName tableName, Admin admin, Table t) throws IOException { 721 insertData(tableName, admin, t, 1); 722 } 723 724 private void insertData(TableName tableName, Admin admin, Table t, int i) throws IOException { 725 Put p = new Put(Bytes.toBytes("row" + i)); 726 p.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("1")); 727 t.put(p); 728 p = new Put(Bytes.toBytes("row" + (i + 1))); 729 p.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("2")); 730 t.put(p); 731 p = new Put(Bytes.toBytes("row" + (i + 2))); 732 p.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("3")); 733 t.put(p); 734 p = new Put(Bytes.toBytes("row" + (i + 3))); 735 p.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("4")); 736 t.put(p); 737 admin.flush(tableName); 738 } 739 740 /** 741 * If a table has regions that have no store files in a region, they should split successfully 742 * into two regions with no store files. 743 */ 744 @Test 745 public void testSplitRegionWithNoStoreFiles() throws Exception { 746 final TableName tableName = TableName.valueOf(name.getMethodName()); 747 // Create table then get the single region for our new table. 748 createTableAndWait(tableName, HConstants.CATALOG_FAMILY); 749 List<HRegion> regions = cluster.getRegions(tableName); 750 RegionInfo hri = getAndCheckSingleTableRegion(regions); 751 ensureTableRegionNotOnSameServerAsMeta(admin, hri); 752 int regionServerIndex = cluster.getServerWith(regions.get(0).getRegionInfo() 753 .getRegionName()); 754 HRegionServer regionServer = cluster.getRegionServer(regionServerIndex); 755 // Turn off balancer so it doesn't cut in and mess up our placements. 756 this.admin.balancerSwitch(false, true); 757 // Turn off the meta scanner so it don't remove parent on us. 758 cluster.getMaster().setCatalogJanitorEnabled(false); 759 try { 760 // Precondition: we created a table with no data, no store files. 761 printOutRegions(regionServer, "Initial regions: "); 762 Configuration conf = cluster.getConfiguration(); 763 HBaseFsck.debugLsr(conf, new Path("/")); 764 Path rootDir = CommonFSUtils.getRootDir(conf); 765 FileSystem fs = TESTING_UTIL.getDFSCluster().getFileSystem(); 766 Map<String, Path> storefiles = 767 FSUtils.getTableStoreFilePathMap(null, fs, rootDir, tableName); 768 assertEquals("Expected nothing but found " + storefiles.toString(), 0, storefiles.size()); 769 770 // find a splittable region. Refresh the regions list 771 regions = cluster.getRegions(tableName); 772 final HRegion region = findSplittableRegion(regions); 773 assertTrue("not able to find a splittable region", region != null); 774 775 // Now split. 776 try { 777 requestSplitRegion(regionServer, region, Bytes.toBytes("row2")); 778 } catch (IOException e) { 779 fail("Split execution should have succeeded with no exceptions thrown"); 780 } 781 782 // Postcondition: split the table with no store files into two regions, but still have no 783 // store files 784 List<HRegion> daughters = cluster.getRegions(tableName); 785 assertEquals(2, daughters.size()); 786 787 // check dirs 788 HBaseFsck.debugLsr(conf, new Path("/")); 789 Map<String, Path> storefilesAfter = 790 FSUtils.getTableStoreFilePathMap(null, fs, rootDir, tableName); 791 assertEquals("Expected nothing but found " + storefilesAfter.toString(), 0, 792 storefilesAfter.size()); 793 794 hri = region.getRegionInfo(); // split parent 795 AssignmentManager am = cluster.getMaster().getAssignmentManager(); 796 RegionStates regionStates = am.getRegionStates(); 797 long start = EnvironmentEdgeManager.currentTime(); 798 while (!regionStates.isRegionInState(hri, State.SPLIT)) { 799 LOG.debug("Waiting for SPLIT state on: " + hri); 800 assertFalse("Timed out in waiting split parent to be in state SPLIT", 801 EnvironmentEdgeManager.currentTime() - start > 60000); 802 Thread.sleep(500); 803 } 804 assertTrue(regionStates.isRegionInState(daughters.get(0).getRegionInfo(), State.OPEN)); 805 assertTrue(regionStates.isRegionInState(daughters.get(1).getRegionInfo(), State.OPEN)); 806 807 // We should not be able to assign it again 808 try { 809 am.assign(hri); 810 } catch (DoNotRetryIOException e) { 811 // Expected 812 } 813 assertFalse("Split region can't be assigned", regionStates.isRegionInTransition(hri)); 814 assertTrue(regionStates.isRegionInState(hri, State.SPLIT)); 815 816 // We should not be able to unassign it either 817 try { 818 am.unassign(hri); 819 fail("Should have thrown exception"); 820 } catch (DoNotRetryIOException e) { 821 // Expected 822 } 823 assertFalse("Split region can't be unassigned", regionStates.isRegionInTransition(hri)); 824 assertTrue(regionStates.isRegionInState(hri, State.SPLIT)); 825 } finally { 826 admin.balancerSwitch(true, false); 827 cluster.getMaster().setCatalogJanitorEnabled(true); 828 } 829 } 830 831 @Test 832 public void testStoreFileReferenceCreationWhenSplitPolicySaysToSkipRangeCheck() 833 throws Exception { 834 final TableName tableName = TableName.valueOf(name.getMethodName()); 835 try { 836 byte[] cf = Bytes.toBytes("f"); 837 byte[] cf1 = Bytes.toBytes("i_f"); 838 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 839 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf)) 840 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf1)) 841 .setRegionSplitPolicyClassName(CustomSplitPolicy.class.getName()).build(); 842 admin.createTable(htd); 843 List<HRegion> regions = awaitTableRegions(tableName); 844 HRegion region = regions.get(0); 845 for(int i = 3;i<9;i++) { 846 Put p = new Put(Bytes.toBytes("row"+i)); 847 p.addColumn(cf, Bytes.toBytes("q"), Bytes.toBytes("value" + i)); 848 p.addColumn(cf1, Bytes.toBytes("q"), Bytes.toBytes("value" + i)); 849 region.put(p); 850 } 851 region.flush(true); 852 HStore store = region.getStore(cf); 853 Collection<HStoreFile> storefiles = store.getStorefiles(); 854 assertEquals(1, storefiles.size()); 855 assertFalse(region.hasReferences()); 856 Path referencePath = 857 region.getRegionFileSystem().splitStoreFile(region.getRegionInfo(), "f", 858 storefiles.iterator().next(), Bytes.toBytes("row1"), false, region.getSplitPolicy()); 859 assertNull(referencePath); 860 referencePath = 861 region.getRegionFileSystem().splitStoreFile(region.getRegionInfo(), "i_f", 862 storefiles.iterator().next(), Bytes.toBytes("row1"), false, region.getSplitPolicy()); 863 assertNotNull(referencePath); 864 } finally { 865 TESTING_UTIL.deleteTable(tableName); 866 } 867 } 868 869 private HRegion findSplittableRegion(final List<HRegion> regions) throws InterruptedException { 870 for (int i = 0; i < 5; ++i) { 871 for (HRegion r: regions) { 872 if (r.isSplittable() && r.getRegionInfo().getReplicaId() == 0) { 873 return(r); 874 } 875 } 876 Thread.sleep(100); 877 } 878 return null; 879 } 880 881 private List<HRegion> checkAndGetDaughters(TableName tableName) throws InterruptedException { 882 List<HRegion> daughters = null; 883 // try up to 10s 884 for (int i = 0; i < 100; i++) { 885 daughters = cluster.getRegions(tableName); 886 if (daughters.size() >= 2) { 887 break; 888 } 889 Thread.sleep(100); 890 } 891 assertTrue(daughters.size() >= 2); 892 return daughters; 893 } 894 895 private HMaster abortAndWaitForMaster() throws IOException, InterruptedException { 896 cluster.abortMaster(0); 897 cluster.waitOnMaster(0); 898 HMaster master = cluster.startMaster().getMaster(); 899 cluster.waitForActiveAndReadyMaster(); 900 // reset the connections 901 IOUtils.closeQuietly(admin); 902 TESTING_UTIL.invalidateConnection(); 903 admin = TESTING_UTIL.getAdmin(); 904 return master; 905 } 906 907 /** 908 * Ensure single table region is not on same server as the single hbase:meta table 909 * region. 910 * @return Index of the server hosting the single table region 911 * @throws UnknownRegionException 912 * @throws MasterNotRunningException 913 * @throws org.apache.hadoop.hbase.ZooKeeperConnectionException 914 * @throws InterruptedException 915 */ 916 private int ensureTableRegionNotOnSameServerAsMeta(final Admin admin, 917 final RegionInfo hri) 918 throws IOException, MasterNotRunningException, 919 ZooKeeperConnectionException, InterruptedException { 920 // Now make sure that the table region is not on same server as that hosting 921 // hbase:meta We don't want hbase:meta replay polluting our test when we later crash 922 // the table region serving server. 923 int metaServerIndex = cluster.getServerWithMeta(); 924 boolean tablesOnMaster = LoadBalancer.isTablesOnMaster(TESTING_UTIL.getConfiguration()); 925 if (tablesOnMaster) { 926 // Need to check master is supposed to host meta... perhaps it is not. 927 throw new UnsupportedOperationException(); 928 // TODO: assertTrue(metaServerIndex == -1); // meta is on master now 929 } 930 HRegionServer metaRegionServer = tablesOnMaster? 931 cluster.getMaster(): cluster.getRegionServer(metaServerIndex); 932 int tableRegionIndex = cluster.getServerWith(hri.getRegionName()); 933 assertTrue(tableRegionIndex != -1); 934 HRegionServer tableRegionServer = cluster.getRegionServer(tableRegionIndex); 935 LOG.info("MetaRegionServer=" + metaRegionServer.getServerName() + 936 ", other=" + tableRegionServer.getServerName()); 937 if (metaRegionServer.getServerName().equals(tableRegionServer.getServerName())) { 938 HRegionServer hrs = getOtherRegionServer(cluster, metaRegionServer); 939 assertNotNull(hrs); 940 assertNotNull(hri); 941 LOG.info("Moving " + hri.getRegionNameAsString() + " from " + 942 metaRegionServer.getServerName() + " to " + 943 hrs.getServerName() + "; metaServerIndex=" + metaServerIndex); 944 admin.move(hri.getEncodedNameAsBytes(), hrs.getServerName()); 945 } 946 // Wait till table region is up on the server that is NOT carrying hbase:meta. 947 for (int i = 0; i < 100; i++) { 948 tableRegionIndex = cluster.getServerWith(hri.getRegionName()); 949 if (tableRegionIndex != -1 && tableRegionIndex != metaServerIndex) break; 950 LOG.debug("Waiting on region move off the hbase:meta server; current index " + 951 tableRegionIndex + " and metaServerIndex=" + metaServerIndex); 952 Thread.sleep(100); 953 } 954 assertTrue("Region not moved off hbase:meta server, tableRegionIndex=" + tableRegionIndex, 955 tableRegionIndex != -1 && tableRegionIndex != metaServerIndex); 956 // Verify for sure table region is not on same server as hbase:meta 957 tableRegionIndex = cluster.getServerWith(hri.getRegionName()); 958 assertTrue(tableRegionIndex != -1); 959 assertNotSame(metaServerIndex, tableRegionIndex); 960 return tableRegionIndex; 961 } 962 963 /** 964 * Find regionserver other than the one passed. 965 * Can't rely on indexes into list of regionservers since crashed servers 966 * occupy an index. 967 * @param cluster 968 * @param notThisOne 969 * @return A regionserver that is not <code>notThisOne</code> or null if none 970 * found 971 */ 972 private HRegionServer getOtherRegionServer(final MiniHBaseCluster cluster, 973 final HRegionServer notThisOne) { 974 for (RegionServerThread rst: cluster.getRegionServerThreads()) { 975 HRegionServer hrs = rst.getRegionServer(); 976 if (hrs.getServerName().equals(notThisOne.getServerName())) continue; 977 if (hrs.isStopping() || hrs.isStopped()) continue; 978 return hrs; 979 } 980 return null; 981 } 982 983 private void printOutRegions(final HRegionServer hrs, final String prefix) 984 throws IOException { 985 List<RegionInfo> regions = ProtobufUtil.getOnlineRegions(hrs.getRSRpcServices()); 986 for (RegionInfo region: regions) { 987 LOG.info(prefix + region.getRegionNameAsString()); 988 } 989 } 990 991 private void waitUntilRegionServerDead() throws InterruptedException, IOException { 992 // Wait until the master processes the RS shutdown 993 for (int i=0; (cluster.getMaster().getClusterMetrics() 994 .getLiveServerMetrics().size() > NB_SERVERS 995 || cluster.getLiveRegionServerThreads().size() > NB_SERVERS) && i<100; i++) { 996 LOG.info("Waiting on server to go down"); 997 Thread.sleep(100); 998 } 999 assertFalse("Waited too long for RS to die", 1000 cluster.getMaster().getClusterMetrics(). getLiveServerMetrics().size() > NB_SERVERS 1001 || cluster.getLiveRegionServerThreads().size() > NB_SERVERS); 1002 } 1003 1004 private void awaitDaughters(TableName tableName, int numDaughters) throws InterruptedException { 1005 // Wait till regions are back on line again. 1006 for (int i = 0; cluster.getRegions(tableName).size() < numDaughters && i < 60; i++) { 1007 LOG.info("Waiting for repair to happen"); 1008 Thread.sleep(1000); 1009 } 1010 if (cluster.getRegions(tableName).size() < numDaughters) { 1011 fail("Waiting too long for daughter regions"); 1012 } 1013 } 1014 1015 private List<HRegion> awaitTableRegions(final TableName tableName) throws InterruptedException { 1016 List<HRegion> regions = null; 1017 for (int i = 0; i < 100; i++) { 1018 regions = cluster.getRegions(tableName); 1019 if (regions.size() > 0) break; 1020 Thread.sleep(100); 1021 } 1022 return regions; 1023 } 1024 1025 private Table createTableAndWait(TableName tableName, byte[] cf) throws IOException, 1026 InterruptedException { 1027 Table t = TESTING_UTIL.createTable(tableName, cf); 1028 awaitTableRegions(tableName); 1029 assertTrue("Table not online: " + tableName, 1030 cluster.getRegions(tableName).size() != 0); 1031 return t; 1032 } 1033 1034 // Make it public so that JVMClusterUtil can access it. 1035 public static class MyMaster extends HMaster { 1036 public MyMaster(Configuration conf) throws IOException, KeeperException, InterruptedException { 1037 super(conf); 1038 } 1039 1040 @Override 1041 protected RSRpcServices createRpcServices() throws IOException { 1042 return new MyMasterRpcServices(this); 1043 } 1044 } 1045 1046 static class MyMasterRpcServices extends MasterRpcServices { 1047 static AtomicBoolean enabled = new AtomicBoolean(false); 1048 1049 private HMaster myMaster; 1050 public MyMasterRpcServices(HMaster master) throws IOException { 1051 super(master); 1052 myMaster = master; 1053 } 1054 1055 @Override 1056 public ReportRegionStateTransitionResponse reportRegionStateTransition(RpcController c, 1057 ReportRegionStateTransitionRequest req) throws ServiceException { 1058 ReportRegionStateTransitionResponse resp = super.reportRegionStateTransition(c, req); 1059 if (enabled.get() && req.getTransition(0).getTransitionCode().equals( 1060 TransitionCode.READY_TO_SPLIT) && !resp.hasErrorMessage()) { 1061 RegionStates regionStates = myMaster.getAssignmentManager().getRegionStates(); 1062 for (RegionStateNode regionState: 1063 regionStates.getRegionsInTransition()) { 1064 /* TODO!!!! 1065 // Find the merging_new region and remove it 1066 if (regionState.isSplittingNew()) { 1067 regionStates.deleteRegion(regionState.getRegion()); 1068 } 1069 */ 1070 } 1071 } 1072 return resp; 1073 } 1074 } 1075 1076 static class CustomSplitPolicy extends IncreasingToUpperBoundRegionSplitPolicy { 1077 1078 @Override 1079 protected boolean shouldSplit() { 1080 return true; 1081 } 1082 1083 @Override 1084 public boolean skipStoreFileRangeCheck(String familyName) { 1085 if(familyName.startsWith("i_")) { 1086 return true; 1087 } else { 1088 return false; 1089 } 1090 } 1091 } 1092} 1093