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.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertNotNull; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023 024import java.util.List; 025import java.util.concurrent.TimeUnit; 026import org.apache.hadoop.hbase.Waiter.ExplainingPredicate; 027import org.apache.hadoop.hbase.client.AsyncConnection; 028import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 029import org.apache.hadoop.hbase.client.ConnectionFactory; 030import org.apache.hadoop.hbase.client.RegionInfo; 031import org.apache.hadoop.hbase.client.TableDescriptor; 032import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 033import org.apache.hadoop.hbase.testclassification.MediumTests; 034import org.apache.hadoop.hbase.testclassification.MiscTests; 035import org.apache.hadoop.hbase.util.Bytes; 036import org.junit.jupiter.api.AfterAll; 037import org.junit.jupiter.api.BeforeAll; 038import org.junit.jupiter.api.Tag; 039import org.junit.jupiter.api.Test; 040 041@Tag(MiscTests.TAG) 042@Tag(MediumTests.TAG) 043public class TestSplitMerge { 044 045 private static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 046 047 @BeforeAll 048 public static void setUp() throws Exception { 049 UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_META_OPERATION_TIMEOUT, 1000); 050 UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2); 051 UTIL.startMiniCluster(1); 052 } 053 054 @AfterAll 055 public static void tearDown() throws Exception { 056 UTIL.shutdownMiniCluster(); 057 } 058 059 @Test 060 public void test() throws Exception { 061 TableName tableName = TableName.valueOf("SplitMerge"); 062 byte[] family = Bytes.toBytes("CF"); 063 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName) 064 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build(); 065 UTIL.getAdmin().createTable(td, new byte[][] { Bytes.toBytes(1) }); 066 UTIL.waitTableAvailable(tableName); 067 UTIL.getAdmin().split(tableName, Bytes.toBytes(2)); 068 UTIL.waitFor(30000, new ExplainingPredicate<Exception>() { 069 070 @Override 071 public boolean evaluate() throws Exception { 072 return UTIL.getMiniHBaseCluster().getRegions(tableName).size() == 3; 073 } 074 075 @Override 076 public String explainFailure() throws Exception { 077 return "Split has not finished yet"; 078 } 079 }); 080 UTIL.waitUntilNoRegionsInTransition(); 081 RegionInfo regionA = null; 082 RegionInfo regionB = null; 083 for (RegionInfo region : UTIL.getAdmin().getRegions(tableName)) { 084 if (region.getStartKey().length == 0) { 085 regionA = region; 086 } else if (Bytes.equals(region.getStartKey(), Bytes.toBytes(1))) { 087 regionB = region; 088 } 089 } 090 assertNotNull(regionA); 091 assertNotNull(regionB); 092 UTIL.getAdmin().mergeRegionsAsync(regionA.getRegionName(), regionB.getRegionName(), false) 093 .get(30, TimeUnit.SECONDS); 094 assertEquals(2, UTIL.getAdmin().getRegions(tableName).size()); 095 096 ServerName expected = UTIL.getMiniHBaseCluster().getRegionServer(0).getServerName(); 097 assertEquals(expected, UTIL.getConnection().getRegionLocator(tableName) 098 .getRegionLocation(Bytes.toBytes(1), true).getServerName()); 099 try (AsyncConnection asyncConn = 100 ConnectionFactory.createAsyncConnection(UTIL.getConfiguration()).get()) { 101 assertEquals(expected, asyncConn.getRegionLocator(tableName) 102 .getRegionLocation(Bytes.toBytes(1), true).get().getServerName()); 103 } 104 } 105 106 @Test 107 public void testMergeRegionOrder() throws Exception { 108 int regionCount = 20; 109 110 TableName tableName = TableName.valueOf("MergeRegionOrder"); 111 byte[] family = Bytes.toBytes("CF"); 112 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName) 113 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build(); 114 115 byte[][] splitKeys = new byte[regionCount - 1][]; 116 117 for (int c = 0; c < regionCount - 1; c++) { 118 splitKeys[c] = Bytes.toBytes(c + 1 * 1000); 119 } 120 121 UTIL.getAdmin().createTable(td, splitKeys); 122 UTIL.waitTableAvailable(tableName); 123 124 List<RegionInfo> regions = UTIL.getAdmin().getRegions(tableName); 125 126 byte[][] regionNames = new byte[regionCount][]; 127 for (int c = 0; c < regionCount; c++) { 128 regionNames[c] = regions.get(c).getRegionName(); 129 } 130 131 UTIL.getAdmin().mergeRegionsAsync(regionNames, false).get(60, TimeUnit.SECONDS); 132 133 List<RegionInfo> mergedRegions = 134 MetaTableAccessor.getTableRegions(UTIL.getConnection(), tableName); 135 136 assertEquals(1, mergedRegions.size()); 137 138 RegionInfo mergedRegion = mergedRegions.get(0); 139 140 List<RegionInfo> mergeParentRegions = UTIL.getMiniHBaseCluster().getMaster() 141 .getAssignmentManager().getRegionStateStore().getMergeRegions(mergedRegion); 142 143 assertEquals(mergeParentRegions.size(), regionCount); 144 145 for (int c = 0; c < regionCount - 1; c++) { 146 assertTrue(Bytes.compareTo(mergeParentRegions.get(c).getStartKey(), 147 mergeParentRegions.get(c + 1).getStartKey()) < 0); 148 } 149 } 150}