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