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.client;
019
020import static org.apache.hadoop.hbase.TableName.META_TABLE_NAME;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertFalse;
023import static org.junit.Assert.assertTrue;
024
025import java.util.ArrayList;
026import java.util.List;
027import org.apache.hadoop.hbase.AsyncMetaTableAccessor;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HConstants;
030import org.apache.hadoop.hbase.HRegionLocation;
031import org.apache.hadoop.hbase.TableName;
032import org.apache.hadoop.hbase.testclassification.ClientTests;
033import org.apache.hadoop.hbase.testclassification.LargeTests;
034import org.apache.hadoop.hbase.util.Bytes;
035import org.apache.hadoop.hbase.util.Threads;
036import org.junit.ClassRule;
037import org.junit.Ignore;
038import org.junit.Test;
039import org.junit.experimental.categories.Category;
040import org.junit.runner.RunWith;
041import org.junit.runners.Parameterized;
042
043/**
044 * Class to test asynchronous region admin operations.
045 * @see TestAsyncRegionAdminApi This test and it used to be joined it was taking longer than our
046 * ten minute timeout so they were split.
047 */
048@RunWith(Parameterized.class)
049@Category({ LargeTests.class, ClientTests.class })
050public class TestAsyncRegionAdminApi2 extends TestAsyncAdminBase {
051
052  @ClassRule
053  public static final HBaseClassTestRule CLASS_RULE =
054      HBaseClassTestRule.forClass(TestAsyncRegionAdminApi2.class);
055
056  @Test
057  public void testGetRegionLocation() throws Exception {
058    RawAsyncHBaseAdmin rawAdmin = (RawAsyncHBaseAdmin) ASYNC_CONN.getAdmin();
059    TEST_UTIL.createMultiRegionTable(tableName, HConstants.CATALOG_FAMILY);
060    AsyncTableRegionLocator locator = ASYNC_CONN.getRegionLocator(tableName);
061    HRegionLocation regionLocation = locator.getRegionLocation(Bytes.toBytes("mmm")).get();
062    RegionInfo region = regionLocation.getRegion();
063    byte[] regionName = regionLocation.getRegion().getRegionName();
064    HRegionLocation location = rawAdmin.getRegionLocation(regionName).get();
065    assertTrue(Bytes.equals(regionName, location.getRegion().getRegionName()));
066    location = rawAdmin.getRegionLocation(region.getEncodedNameAsBytes()).get();
067    assertTrue(Bytes.equals(regionName, location.getRegion().getRegionName()));
068  }
069
070  @Test
071  public void testSplitSwitch() throws Exception {
072    createTableWithDefaultConf(tableName);
073    byte[][] families = {FAMILY};
074    final int rows = 10000;
075    TestAsyncRegionAdminApi.loadData(tableName, families, rows);
076
077    AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME);
078    List<HRegionLocation> regionLocations =
079        AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get();
080    int originalCount = regionLocations.size();
081
082    initSplitMergeSwitch();
083    assertTrue(admin.splitSwitch(false).get());
084    try {
085      admin.split(tableName, Bytes.toBytes(rows / 2)).join();
086    } catch (Exception e) {
087      //Expected
088    }
089    int count = admin.getRegions(tableName).get().size();
090    assertTrue(originalCount == count);
091
092    assertFalse(admin.splitSwitch(true).get());
093    admin.split(tableName).join();
094    while ((count = admin.getRegions(tableName).get().size()) == originalCount) {
095      Threads.sleep(100);
096    }
097    assertTrue(originalCount < count);
098  }
099
100  @Test
101  @Ignore
102  // It was ignored in TestSplitOrMergeStatus, too
103  public void testMergeSwitch() throws Exception {
104    createTableWithDefaultConf(tableName);
105    byte[][] families = {FAMILY};
106    TestAsyncRegionAdminApi.loadData(tableName, families, 1000);
107
108    AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME);
109    List<HRegionLocation> regionLocations =
110        AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get();
111    int originalCount = regionLocations.size();
112
113    initSplitMergeSwitch();
114    admin.split(tableName).join();
115    int postSplitCount = originalCount;
116    while ((postSplitCount = admin.getRegions(tableName).get().size()) == originalCount) {
117      Threads.sleep(100);
118    }
119    assertTrue("originalCount=" + originalCount + ", postSplitCount=" + postSplitCount,
120        originalCount != postSplitCount);
121
122    // Merge switch is off so merge should NOT succeed.
123    assertTrue(admin.mergeSwitch(false).get());
124    List<RegionInfo> regions = admin.getRegions(tableName).get();
125    assertTrue(regions.size() > 1);
126    admin.mergeRegions(regions.get(0).getRegionName(), regions.get(1).getRegionName(), true).join();
127    int count = admin.getRegions(tableName).get().size();
128    assertTrue("postSplitCount=" + postSplitCount + ", count=" + count, postSplitCount == count);
129
130    // Merge switch is on so merge should succeed.
131    assertFalse(admin.mergeSwitch(true).get());
132    admin.mergeRegions(regions.get(0).getRegionName(), regions.get(1).getRegionName(), true).join();
133    count = admin.getRegions(tableName).get().size();
134    assertTrue((postSplitCount / 2) == count);
135  }
136
137  private void initSplitMergeSwitch() throws Exception {
138    if (!admin.isSplitEnabled().get()) {
139      admin.splitSwitch(true).get();
140    }
141    if (!admin.isMergeEnabled().get()) {
142      admin.mergeSwitch(true).get();
143    }
144    assertTrue(admin.isSplitEnabled().get());
145    assertTrue(admin.isMergeEnabled().get());
146  }
147
148  @Test
149  public void testMergeRegions() throws Exception {
150    byte[][] splitRows = new byte[][]{Bytes.toBytes("3"), Bytes.toBytes("6")};
151    createTableWithDefaultConf(tableName, splitRows);
152
153    AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME);
154    List<HRegionLocation> regionLocations = AsyncMetaTableAccessor
155      .getTableHRegionLocations(metaTable, tableName).get();
156    RegionInfo regionA;
157    RegionInfo regionB;
158
159    // merge with full name
160    assertEquals(3, regionLocations.size());
161    regionA = regionLocations.get(0).getRegion();
162    regionB = regionLocations.get(1).getRegion();
163    admin.mergeRegions(regionA.getRegionName(), regionB.getRegionName(), false).get();
164
165    regionLocations = AsyncMetaTableAccessor
166      .getTableHRegionLocations(metaTable, tableName).get();
167    assertEquals(2, regionLocations.size());
168    // merge with encoded name
169    regionA = regionLocations.get(0).getRegion();
170    regionB = regionLocations.get(1).getRegion();
171    admin.mergeRegions(regionA.getRegionName(), regionB.getRegionName(), false).get();
172
173    regionLocations = AsyncMetaTableAccessor
174      .getTableHRegionLocations(metaTable, tableName).get();
175    assertEquals(1, regionLocations.size());
176  }
177
178  @Test
179  public void testSplitTable() throws Exception {
180    initSplitMergeSwitch();
181    splitTest(TableName.valueOf("testSplitTable"), 3000, false, null);
182    splitTest(TableName.valueOf("testSplitTableWithSplitPoint"), 3000, false, Bytes.toBytes("3"));
183    splitTest(TableName.valueOf("testSplitTableRegion"), 3000, true, null);
184    splitTest(TableName.valueOf("testSplitTableRegionWithSplitPoint2"), 3000, true, Bytes.toBytes("3"));
185  }
186
187  private void
188  splitTest(TableName tableName, int rowCount, boolean isSplitRegion, byte[] splitPoint)
189      throws Exception {
190    // create table
191    createTableWithDefaultConf(tableName);
192
193    AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME);
194    List<HRegionLocation> regionLocations = AsyncMetaTableAccessor
195      .getTableHRegionLocations(metaTable, tableName).get();
196    assertEquals(1, regionLocations.size());
197
198    AsyncTable<?> table = ASYNC_CONN.getTable(tableName);
199    List<Put> puts = new ArrayList<>();
200    for (int i = 0; i < rowCount; i++) {
201      Put put = new Put(Bytes.toBytes(i));
202      put.addColumn(FAMILY, null, Bytes.toBytes("value" + i));
203      puts.add(put);
204    }
205    table.putAll(puts).join();
206
207    if (isSplitRegion) {
208      if (splitPoint == null) {
209        admin.splitRegion(regionLocations.get(0).getRegion().getRegionName()).get();
210      } else {
211        admin.splitRegion(regionLocations.get(0).getRegion().getRegionName(), splitPoint).get();
212      }
213    } else {
214      if (splitPoint == null) {
215        admin.split(tableName).get();
216      } else {
217        admin.split(tableName, splitPoint).get();
218      }
219    }
220
221    int count = 0;
222    for (int i = 0; i < 45; i++) {
223      try {
224        regionLocations = AsyncMetaTableAccessor
225          .getTableHRegionLocations(metaTable, tableName).get();
226        count = regionLocations.size();
227        if (count >= 2) {
228          break;
229        }
230        Thread.sleep(1000L);
231      } catch (Exception e) {
232        LOG.error(e.toString(), e);
233      }
234    }
235    assertEquals(2, count);
236  }
237}