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