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 HBaseTestingUtil UTIL = new HBaseTestingUtil();
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 = UTIL.getMiniHBaseCluster().getMaster()
145      .getAssignmentManager().getRegionStateStore().getMergeRegions(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}