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.master.assignment;
019
020import static org.apache.hadoop.hbase.master.assignment.AssignmentTestingUtil.insertData;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertNotEquals;
023import static org.junit.Assert.assertTrue;
024
025import java.util.List;
026import java.util.Map;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.HConstants;
031import org.apache.hadoop.hbase.ServerName;
032import org.apache.hadoop.hbase.StartMiniClusterOption;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.client.RegionInfo;
035import org.apache.hadoop.hbase.client.TableDescriptor;
036import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
037import org.apache.hadoop.hbase.master.procedure.MasterProcedureTestingUtility;
038import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
039import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
040import org.apache.hadoop.hbase.regionserver.HRegion;
041import org.apache.hadoop.hbase.testclassification.MasterTests;
042import org.apache.hadoop.hbase.testclassification.MediumTests;
043import org.apache.hadoop.hbase.util.Bytes;
044import org.apache.hadoop.hbase.util.JVMClusterUtil;
045import org.junit.After;
046import org.junit.AfterClass;
047import org.junit.Before;
048import org.junit.BeforeClass;
049import org.junit.ClassRule;
050import org.junit.Rule;
051import org.junit.Test;
052import org.junit.experimental.categories.Category;
053import org.junit.rules.TestName;
054import org.slf4j.Logger;
055import org.slf4j.LoggerFactory;
056
057@Category({ MasterTests.class, MediumTests.class })
058public class TestRegionSplitAndSeparateChildren {
059
060  @ClassRule
061  public static final HBaseClassTestRule CLASS_RULE =
062    HBaseClassTestRule.forClass(TestRegionSplitAndSeparateChildren.class);
063
064  private static final Logger LOG =
065    LoggerFactory.getLogger(TestRegionSplitAndSeparateChildren.class);
066
067  protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
068
069  private static String columnFamilyName = "cf";
070
071  private static final int startRowNum = 11;
072  private static final int rowCount = 60;
073
074  @Rule
075  public TestName name = new TestName();
076
077  private static void setupConf(Configuration conf) {
078    // enable automatically separate child regions
079    conf.setBoolean(HConstants.HBASE_ENABLE_SEPARATE_CHILD_REGIONS, true);
080  }
081
082  @BeforeClass
083  public static void setupCluster() throws Exception {
084    setupConf(UTIL.getConfiguration());
085    StartMiniClusterOption option =
086      StartMiniClusterOption.builder().numMasters(1).numRegionServers(3).numDataNodes(3).build();
087    UTIL.startMiniCluster(option);
088  }
089
090  @AfterClass
091  public static void cleanupTest() throws Exception {
092    try {
093      UTIL.shutdownMiniCluster();
094    } catch (Exception e) {
095      LOG.warn("failure shutting down cluster", e);
096    }
097  }
098
099  @Before
100  public void setup() throws Exception {
101    // Turn off the meta scanner so it don't remove parent on us.
102    UTIL.getHBaseCluster().getMaster().setCatalogJanitorEnabled(false);
103    // Disable compaction.
104    for (int i = 0; i < UTIL.getHBaseCluster().getLiveRegionServerThreads().size(); i++) {
105      UTIL.getHBaseCluster().getRegionServer(i).getCompactSplitThread().switchCompaction(false);
106    }
107  }
108
109  @After
110  public void tearDown() throws Exception {
111    for (TableDescriptor htd : UTIL.getAdmin().listTableDescriptors()) {
112      UTIL.deleteTable(htd.getTableName());
113    }
114  }
115
116  @Test
117  public void testSplitTableRegionAndSeparateChildRegions() throws Exception {
118    final TableName tableName = TableName.valueOf(name.getMethodName());
119    final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
120
121    RegionInfo[] regions =
122      MasterProcedureTestingUtility.createTable(procExec, tableName, null, columnFamilyName);
123    insertData(UTIL, tableName, rowCount, startRowNum, columnFamilyName);
124    int splitRowNum = startRowNum + rowCount / 2;
125    byte[] splitKey = Bytes.toBytes("" + splitRowNum);
126
127    assertTrue("not able to find a splittable region", regions != null);
128    assertTrue("not able to find a splittable region", regions.length == 1);
129
130    // Split region of the table
131    long procId = procExec.submitProcedure(
132      new SplitTableRegionProcedure(procExec.getEnvironment(), regions[0], splitKey));
133    // Wait the completion
134    ProcedureTestingUtility.waitProcedure(procExec, procId);
135    ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
136
137    assertTrue("not able to split table", UTIL.getHBaseCluster().getRegions(tableName).size() == 2);
138
139    // disable table
140    UTIL.getAdmin().disableTable(tableName);
141    Thread.sleep(500);
142
143    // stop master
144    UTIL.getHBaseCluster().stopMaster(0);
145    UTIL.getHBaseCluster().waitOnMaster(0);
146    Thread.sleep(500);
147
148    // restart master
149    JVMClusterUtil.MasterThread t = UTIL.getHBaseCluster().startMaster();
150    Thread.sleep(500);
151
152    UTIL.invalidateConnection();
153    // enable table
154    UTIL.getAdmin().enableTable(tableName);
155    Thread.sleep(500);
156
157    List<HRegion> tableRegions = UTIL.getHBaseCluster().getRegions(tableName);
158    assertEquals("Table region not correct.", 2, tableRegions.size());
159    Map<RegionInfo, ServerName> regionInfoMap = UTIL.getHBaseCluster().getMaster()
160      .getAssignmentManager().getRegionStates().getRegionAssignments();
161    assertNotEquals(regionInfoMap.get(tableRegions.get(0).getRegionInfo()),
162      regionInfoMap.get(tableRegions.get(1).getRegionInfo()));
163  }
164
165  private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
166    return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
167  }
168}