2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.client
;
20 import static org
.junit
.Assert
.assertFalse
;
21 import static org
.junit
.Assert
.assertTrue
;
22 import static org
.junit
.Assert
.fail
;
24 import java
.util
.List
;
25 import java
.util
.concurrent
.ExecutionException
;
26 import java
.util
.concurrent
.Future
;
27 import java
.util
.concurrent
.TimeUnit
;
28 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
29 import org
.apache
.hadoop
.hbase
.HBaseTestingUtility
;
30 import org
.apache
.hadoop
.hbase
.TableName
;
31 import org
.apache
.hadoop
.hbase
.Waiter
.ExplainingPredicate
;
32 import org
.apache
.hadoop
.hbase
.testclassification
.ClientTests
;
33 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
34 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
35 import org
.apache
.hadoop
.hbase
.util
.Threads
;
36 import org
.junit
.AfterClass
;
37 import org
.junit
.BeforeClass
;
38 import org
.junit
.ClassRule
;
39 import org
.junit
.Rule
;
40 import org
.junit
.Test
;
41 import org
.junit
.experimental
.categories
.Category
;
42 import org
.junit
.rules
.TestName
;
44 @Category({ MediumTests
.class, ClientTests
.class })
45 public class TestSplitOrMergeAtTableLevel
{
48 public static final HBaseClassTestRule CLASS_RULE
=
49 HBaseClassTestRule
.forClass(TestSplitOrMergeAtTableLevel
.class);
51 private final static HBaseTestingUtility TEST_UTIL
= new HBaseTestingUtility();
52 private static byte[] FAMILY
= Bytes
.toBytes("testFamily");
55 public TestName name
= new TestName();
56 private static Admin admin
;
59 public static void setUpBeforeClass() throws Exception
{
60 TEST_UTIL
.startMiniCluster(2);
61 admin
= TEST_UTIL
.getAdmin();
65 public static void tearDownAfterClass() throws Exception
{
66 TEST_UTIL
.shutdownMiniCluster();
70 public void testTableSplitSwitch() throws Exception
{
71 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
72 TableDescriptor tableDesc
= TableDescriptorBuilder
.newBuilder(tableName
)
73 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of(FAMILY
))
74 .setSplitEnabled(false).build();
76 // create a table with split disabled
77 Table t
= TEST_UTIL
.createTable(tableDesc
, null);
78 TEST_UTIL
.waitTableAvailable(tableName
);
80 // load data into the table
81 TEST_UTIL
.loadTable(t
, FAMILY
, false);
83 assertTrue(admin
.getRegions(tableName
).size() == 1);
85 // check that we have split disabled
86 assertFalse(admin
.getDescriptor(tableName
).isSplitEnabled());
87 trySplitAndEnsureItFails(tableName
);
88 enableTableSplit(tableName
);
89 trySplitAndEnsureItIsSuccess(tableName
);
93 public void testTableSplitSwitchForPreSplittedTable() throws Exception
{
94 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
96 // create a table with split disabled
97 TableDescriptor tableDesc
= TableDescriptorBuilder
.newBuilder(tableName
)
98 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of(FAMILY
))
99 .setSplitEnabled(false)
101 Table t
= TEST_UTIL
.createTable(tableDesc
, new byte[][] { Bytes
.toBytes(10) });
102 TEST_UTIL
.waitTableAvailable(tableName
);
104 // load data into the table
105 TEST_UTIL
.loadTable(t
, FAMILY
, false);
107 assertTrue(admin
.getRegions(tableName
).size() == 2);
109 // check that we have split disabled
110 assertFalse(admin
.getDescriptor(tableName
).isSplitEnabled());
111 trySplitAndEnsureItFails(tableName
);
112 enableTableSplit(tableName
);
113 trySplitAndEnsureItIsSuccess(tableName
);
117 public void testTableMergeSwitch() throws Exception
{
118 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
120 TableDescriptor tableDesc
= TableDescriptorBuilder
.newBuilder(tableName
)
121 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of(FAMILY
))
122 .setMergeEnabled(false)
125 Table t
= TEST_UTIL
.createTable(tableDesc
, null);
126 TEST_UTIL
.waitTableAvailable(tableName
);
127 TEST_UTIL
.loadTable(t
, FAMILY
, false);
129 // check merge is disabled for the table
130 assertFalse(admin
.getDescriptor(tableName
).isMergeEnabled());
132 trySplitAndEnsureItIsSuccess(tableName
);
133 Threads
.sleep(10000);
134 tryMergeAndEnsureItFails(tableName
);
135 admin
.disableTable(tableName
);
136 enableTableMerge(tableName
);
137 admin
.enableTable(tableName
);
138 tryMergeAndEnsureItIsSuccess(tableName
);
142 public void testTableMergeSwitchForPreSplittedTable() throws Exception
{
143 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
145 TableDescriptor tableDesc
= TableDescriptorBuilder
.newBuilder(tableName
)
146 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of(FAMILY
))
147 .setMergeEnabled(false)
150 Table t
= TEST_UTIL
.createTable(tableDesc
, new byte[][] { Bytes
.toBytes(10) });
151 TEST_UTIL
.waitTableAvailable(tableName
);
152 TEST_UTIL
.loadTable(t
, FAMILY
, false);
154 // check merge is disabled for the table
155 assertFalse(admin
.getDescriptor(tableName
).isMergeEnabled());
156 assertTrue(admin
.getRegions(tableName
).size() == 2);
157 tryMergeAndEnsureItFails(tableName
);
158 enableTableMerge(tableName
);
159 tryMergeAndEnsureItIsSuccess(tableName
);
162 private void trySplitAndEnsureItFails(final TableName tableName
) throws Exception
{
163 // get the original table region count
164 List
<RegionInfo
> regions
= admin
.getRegions(tableName
);
165 int originalCount
= regions
.size();
167 // split the table and make sure region count does not increase
168 Future
<?
> f
= admin
.splitRegionAsync(regions
.get(0).getEncodedNameAsBytes(), Bytes
.toBytes(2));
170 f
.get(10, TimeUnit
.SECONDS
);
171 fail("Should not get here.");
172 } catch (ExecutionException ee
) {
173 // expected to reach here
174 // check and ensure that table does not get splitted
175 assertTrue(admin
.getRegions(tableName
).size() == originalCount
);
180 * Method to enable split for the passed table and validate this modification.
181 * @param tableName name of the table
183 private void enableTableSplit(final TableName tableName
) throws Exception
{
184 // Get the original table descriptor
185 TableDescriptor originalTableDesc
= admin
.getDescriptor(tableName
);
186 TableDescriptor modifiedTableDesc
= TableDescriptorBuilder
.newBuilder(originalTableDesc
)
187 .setSplitEnabled(true)
190 // Now modify the table descriptor and enable split for it
191 admin
.modifyTable(modifiedTableDesc
);
193 // Verify that split is enabled
194 assertTrue(admin
.getDescriptor(tableName
).isSplitEnabled());
197 private void trySplitAndEnsureItIsSuccess(final TableName tableName
)
199 // get the original table region count
200 List
<RegionInfo
> regions
= admin
.getRegions(tableName
);
201 int originalCount
= regions
.size();
203 // split the table and wait until region count increases
204 admin
.split(tableName
, Bytes
.toBytes(3));
205 TEST_UTIL
.waitFor(30000, new ExplainingPredicate
<Exception
>() {
208 public boolean evaluate() throws Exception
{
209 return admin
.getRegions(tableName
).size() > originalCount
;
213 public String
explainFailure() throws Exception
{
214 return "Split has not finished yet";
219 private void tryMergeAndEnsureItFails(final TableName tableName
) throws Exception
{
220 // assert we have at least 2 regions in the table
221 List
<RegionInfo
> regions
= admin
.getRegions(tableName
);
222 int originalCount
= regions
.size();
223 assertTrue(originalCount
>= 2);
225 byte[] nameOfRegionA
= regions
.get(0).getEncodedNameAsBytes();
226 byte[] nameOfRegionB
= regions
.get(1).getEncodedNameAsBytes();
228 // check and ensure that region do not get merged
229 Future
<?
> f
= admin
.mergeRegionsAsync(nameOfRegionA
, nameOfRegionB
, true);
231 f
.get(10, TimeUnit
.SECONDS
);
232 fail("Should not get here.");
233 } catch (ExecutionException ee
) {
234 // expected to reach here
235 // check and ensure that region do not get merged
236 assertTrue(admin
.getRegions(tableName
).size() == originalCount
);
242 * Method to enable merge for the passed table and validate this modification.
243 * @param tableName name of the table
245 private void enableTableMerge(final TableName tableName
) throws Exception
{
246 // Get the original table descriptor
247 TableDescriptor originalTableDesc
= admin
.getDescriptor(tableName
);
248 TableDescriptor modifiedTableDesc
= TableDescriptorBuilder
.newBuilder(originalTableDesc
)
249 .setMergeEnabled(true)
252 // Now modify the table descriptor and enable merge for it
253 admin
.modifyTable(modifiedTableDesc
);
255 // Verify that merge is enabled
256 assertTrue(admin
.getDescriptor(tableName
).isMergeEnabled());
259 private void tryMergeAndEnsureItIsSuccess(final TableName tableName
) throws Exception
{
260 // assert we have at least 2 regions in the table
261 List
<RegionInfo
> regions
= admin
.getRegions(tableName
);
262 int originalCount
= regions
.size();
263 assertTrue(originalCount
>= 2);
265 byte[] nameOfRegionA
= regions
.get(0).getEncodedNameAsBytes();
266 byte[] nameOfRegionB
= regions
.get(1).getEncodedNameAsBytes();
268 // merge the table regions and wait until region count decreases
269 admin
.mergeRegionsAsync(nameOfRegionA
, nameOfRegionB
, true);
270 TEST_UTIL
.waitFor(30000, new ExplainingPredicate
<Exception
>() {
273 public boolean evaluate() throws Exception
{
274 return admin
.getRegions(tableName
).size() < originalCount
;
278 public String
explainFailure() throws Exception
{
279 return "Merge has not finished yet";