HBASE-26248 Should find a suitable way to let users specify the store file tracker...
[hbase.git] / hbase-server / src / test / java / org / apache / hadoop / hbase / client / TestAsyncTableAdminApi.java
blob147630b53a38ffe21d2618d1bc728c986146cc72
1 /**
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.apache.hadoop.hbase.TableName.META_TABLE_NAME;
21 import static org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory.TRACKER_IMPL;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Optional;
30 import java.util.concurrent.CompletionException;
31 import org.apache.hadoop.hbase.ClientMetaTableAccessor;
32 import org.apache.hadoop.hbase.HBaseClassTestRule;
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.hadoop.hbase.HRegionLocation;
35 import org.apache.hadoop.hbase.TableExistsException;
36 import org.apache.hadoop.hbase.TableName;
37 import org.apache.hadoop.hbase.TableNotFoundException;
38 import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;
39 import org.apache.hadoop.hbase.testclassification.ClientTests;
40 import org.apache.hadoop.hbase.testclassification.LargeTests;
41 import org.apache.hadoop.hbase.util.Bytes;
42 import org.junit.ClassRule;
43 import org.junit.Test;
44 import org.junit.experimental.categories.Category;
45 import org.junit.runner.RunWith;
46 import org.junit.runners.Parameterized;
48 /**
49 * Class to test asynchronous table admin operations.
50 * @see TestAsyncTableAdminApi2 This test and it used to be joined it was taking longer than our
51 * ten minute timeout so they were split.
52 * @see TestAsyncTableAdminApi3 Another split out from this class so each runs under ten minutes.
54 @RunWith(Parameterized.class)
55 @Category({ LargeTests.class, ClientTests.class })
56 public class TestAsyncTableAdminApi extends TestAsyncAdminBase {
58 @ClassRule
59 public static final HBaseClassTestRule CLASS_RULE =
60 HBaseClassTestRule.forClass(TestAsyncTableAdminApi.class);
62 @Test
63 public void testCreateTable() throws Exception {
64 List<TableDescriptor> tables = admin.listTableDescriptors().get();
65 int numTables = tables.size();
66 createTableWithDefaultConf(tableName);
67 tables = admin.listTableDescriptors().get();
68 assertEquals(numTables + 1, tables.size());
69 assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster().getMaster()
70 .getTableStateManager().isTableState(tableName, TableState.State.ENABLED));
71 assertEquals(TableState.State.ENABLED, getStateFromMeta(tableName));
74 static TableState.State getStateFromMeta(TableName table) throws Exception {
75 Optional<TableState> state = ClientMetaTableAccessor
76 .getTableState(ASYNC_CONN.getTable(TableName.META_TABLE_NAME), table).get();
77 assertTrue(state.isPresent());
78 return state.get().getState();
81 @Test
82 public void testCreateTableNumberOfRegions() throws Exception {
83 AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME);
85 createTableWithDefaultConf(tableName);
86 List<HRegionLocation> regionLocations = ClientMetaTableAccessor
87 .getTableHRegionLocations(metaTable, tableName).get();
88 assertEquals("Table should have only 1 region", 1, regionLocations.size());
90 final TableName tableName2 = TableName.valueOf(tableName.getNameAsString() + "_2");
91 createTableWithDefaultConf(tableName2, new byte[][] { new byte[] { 42 } });
92 regionLocations = ClientMetaTableAccessor.getTableHRegionLocations(metaTable, tableName2).get();
93 assertEquals("Table should have only 2 region", 2, regionLocations.size());
95 final TableName tableName3 = TableName.valueOf(tableName.getNameAsString() + "_3");
96 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName3);
97 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY));
98 admin.createTable(builder.build(), Bytes.toBytes("a"), Bytes.toBytes("z"), 3).join();
99 regionLocations = ClientMetaTableAccessor.getTableHRegionLocations(metaTable, tableName3).get();
100 assertEquals("Table should have only 3 region", 3, regionLocations.size());
102 final TableName tableName4 = TableName.valueOf(tableName.getNameAsString() + "_4");
103 builder = TableDescriptorBuilder.newBuilder(tableName4);
104 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY));
105 try {
106 admin.createTable(builder.build(), Bytes.toBytes("a"), Bytes.toBytes("z"), 2).join();
107 fail("Should not be able to create a table with only 2 regions using this API.");
108 } catch (CompletionException e) {
109 assertTrue(e.getCause() instanceof IllegalArgumentException);
112 final TableName tableName5 = TableName.valueOf(tableName.getNameAsString() + "_5");
113 builder = TableDescriptorBuilder.newBuilder(tableName5);
114 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY));
115 admin.createTable(builder.build(), new byte[] { 1 }, new byte[] { 127 }, 16).join();
116 regionLocations = ClientMetaTableAccessor.getTableHRegionLocations(metaTable, tableName5).get();
117 assertEquals("Table should have 16 region", 16, regionLocations.size());
120 @Test
121 public void testCreateTableWithRegions() throws Exception {
122 byte[][] splitKeys = { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, new byte[] { 3, 3, 3 },
123 new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 }, new byte[] { 6, 6, 6 },
124 new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 }, new byte[] { 9, 9, 9 }, };
125 int expectedRegions = splitKeys.length + 1;
126 createTableWithDefaultConf(tableName, splitKeys);
128 boolean tableAvailable = admin.isTableAvailable(tableName).get();
129 assertTrue("Table should be created with splitKyes + 1 rows in META", tableAvailable);
131 AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME);
132 List<HRegionLocation> regions = ClientMetaTableAccessor
133 .getTableHRegionLocations(metaTable, tableName).get();
134 Iterator<HRegionLocation> hris = regions.iterator();
136 assertEquals(
137 "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(),
138 expectedRegions, regions.size());
139 System.err.println("Found " + regions.size() + " regions");
141 RegionInfo hri;
142 hris = regions.iterator();
143 hri = hris.next().getRegion();
144 assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
145 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[0]));
146 hri = hris.next().getRegion();
147 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[0]));
148 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[1]));
149 hri = hris.next().getRegion();
150 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[1]));
151 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[2]));
152 hri = hris.next().getRegion();
153 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[2]));
154 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[3]));
155 hri = hris.next().getRegion();
156 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[3]));
157 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[4]));
158 hri = hris.next().getRegion();
159 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[4]));
160 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[5]));
161 hri = hris.next().getRegion();
162 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[5]));
163 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[6]));
164 hri = hris.next().getRegion();
165 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[6]));
166 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[7]));
167 hri = hris.next().getRegion();
168 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[7]));
169 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[8]));
170 hri = hris.next().getRegion();
171 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[8]));
172 assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
174 // Now test using start/end with a number of regions
176 // Use 80 bit numbers to make sure we aren't limited
177 byte[] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
178 byte[] endKey = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
180 // Splitting into 10 regions, we expect (null,1) ... (9, null)
181 // with (1,2) (2,3) (3,4) (4,5) (5,6) (6,7) (7,8) (8,9) in the middle
182 expectedRegions = 10;
183 final TableName tableName2 = TableName.valueOf(tableName.getNameAsString() + "_2");
184 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName2);
185 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY));
186 admin.createTable(builder.build(), startKey, endKey, expectedRegions).join();
188 regions = ClientMetaTableAccessor.getTableHRegionLocations(metaTable, tableName2).get();
189 assertEquals(
190 "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(),
191 expectedRegions, regions.size());
192 System.err.println("Found " + regions.size() + " regions");
194 hris = regions.iterator();
195 hri = hris.next().getRegion();
196 assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
197 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }));
198 hri = hris.next().getRegion();
199 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }));
200 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }));
201 hri = hris.next().getRegion();
202 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }));
203 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }));
204 hri = hris.next().getRegion();
205 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }));
206 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }));
207 hri = hris.next().getRegion();
208 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }));
209 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }));
210 hri = hris.next().getRegion();
211 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }));
212 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }));
213 hri = hris.next().getRegion();
214 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }));
215 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }));
216 hri = hris.next().getRegion();
217 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }));
218 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }));
219 hri = hris.next().getRegion();
220 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }));
221 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }));
222 hri = hris.next().getRegion();
223 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }));
224 assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
226 // Try once more with something that divides into something infinite
227 startKey = new byte[] { 0, 0, 0, 0, 0, 0 };
228 endKey = new byte[] { 1, 0, 0, 0, 0, 0 };
230 expectedRegions = 5;
231 final TableName tableName3 = TableName.valueOf(tableName.getNameAsString() + "_3");
232 builder = TableDescriptorBuilder.newBuilder(tableName3);
233 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY));
234 admin.createTable(builder.build(), startKey, endKey, expectedRegions).join();
236 regions = ClientMetaTableAccessor.getTableHRegionLocations(metaTable, tableName3)
237 .get();
238 assertEquals(
239 "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(),
240 expectedRegions, regions.size());
241 System.err.println("Found " + regions.size() + " regions");
243 // Try an invalid case where there are duplicate split keys
244 splitKeys = new byte[][] { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 },
245 new byte[] { 3, 3, 3 }, new byte[] { 2, 2, 2 } };
246 final TableName tableName4 = TableName.valueOf(tableName.getNameAsString() + "_4");
247 try {
248 createTableWithDefaultConf(tableName4, splitKeys);
249 fail("Should not be able to create this table because of " + "duplicate split keys");
250 } catch (CompletionException e) {
251 assertTrue(e.getCause() instanceof IllegalArgumentException);
255 @Test
256 public void testCreateTableWithOnlyEmptyStartRow() throws Exception {
257 byte[][] splitKeys = new byte[1][];
258 splitKeys[0] = HConstants.EMPTY_BYTE_ARRAY;
259 try {
260 createTableWithDefaultConf(tableName, splitKeys);
261 fail("Test case should fail as empty split key is passed.");
262 } catch (CompletionException e) {
263 assertTrue(e.getCause() instanceof IllegalArgumentException);
267 @Test
268 public void testCreateTableWithEmptyRowInTheSplitKeys() throws Exception {
269 byte[][] splitKeys = new byte[3][];
270 splitKeys[0] = Bytes.toBytes("region1");
271 splitKeys[1] = HConstants.EMPTY_BYTE_ARRAY;
272 splitKeys[2] = Bytes.toBytes("region2");
273 try {
274 createTableWithDefaultConf(tableName, splitKeys);
275 fail("Test case should fail as empty split key is passed.");
276 } catch (CompletionException e) {
277 assertTrue(e.getCause() instanceof IllegalArgumentException);
281 @Test
282 public void testDeleteTable() throws Exception {
283 createTableWithDefaultConf(tableName);
284 assertTrue(admin.tableExists(tableName).get());
285 TEST_UTIL.getAdmin().disableTable(tableName);
286 admin.deleteTable(tableName).join();
287 assertFalse(admin.tableExists(tableName).get());
290 @Test
291 public void testTruncateTable() throws Exception {
292 testTruncateTable(tableName, false);
295 @Test
296 public void testTruncateTablePreservingSplits() throws Exception {
297 testTruncateTable(tableName, true);
300 private void testTruncateTable(final TableName tableName, boolean preserveSplits)
301 throws Exception {
302 byte[][] splitKeys = new byte[2][];
303 splitKeys[0] = Bytes.toBytes(4);
304 splitKeys[1] = Bytes.toBytes(8);
306 // Create & Fill the table
307 createTableWithDefaultConf(tableName, splitKeys);
308 AsyncTable<?> table = ASYNC_CONN.getTable(tableName);
309 int expectedRows = 10;
310 for (int i = 0; i < expectedRows; i++) {
311 byte[] data = Bytes.toBytes(String.valueOf(i));
312 Put put = new Put(data);
313 put.addColumn(FAMILY, null, data);
314 table.put(put).join();
316 assertEquals(10, table.scanAll(new Scan()).get().size());
317 assertEquals(3, TEST_UTIL.getHBaseCluster().getRegions(tableName).size());
319 // Truncate & Verify
320 admin.disableTable(tableName).join();
321 admin.truncateTable(tableName, preserveSplits).join();
322 assertEquals(0, table.scanAll(new Scan()).get().size());
323 if (preserveSplits) {
324 assertEquals(3, TEST_UTIL.getHBaseCluster().getRegions(tableName).size());
325 } else {
326 assertEquals(1, TEST_UTIL.getHBaseCluster().getRegions(tableName).size());
330 @Test
331 public void testCloneTableSchema() throws Exception {
332 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new");
333 testCloneTableSchema(tableName, newTableName, false);
336 @Test
337 public void testCloneTableSchemaPreservingSplits() throws Exception {
338 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new");
339 testCloneTableSchema(tableName, newTableName, true);
342 private void testCloneTableSchema(final TableName tableName,
343 final TableName newTableName, boolean preserveSplits) throws Exception {
344 byte[][] splitKeys = new byte[2][];
345 splitKeys[0] = Bytes.toBytes(4);
346 splitKeys[1] = Bytes.toBytes(8);
347 int NUM_FAMILYS = 2;
348 int NUM_REGIONS = 3;
349 int BLOCK_SIZE = 1024;
350 int TTL = 86400;
351 boolean BLOCK_CACHE = false;
353 // Create the table
354 TableDescriptor tableDesc = TableDescriptorBuilder
355 .newBuilder(tableName)
356 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_0))
357 .setColumnFamily(ColumnFamilyDescriptorBuilder
358 .newBuilder(FAMILY_1)
359 .setBlocksize(BLOCK_SIZE)
360 .setBlockCacheEnabled(BLOCK_CACHE)
361 .setTimeToLive(TTL)
362 .build()).build();
363 admin.createTable(tableDesc, splitKeys).join();
365 assertEquals(NUM_REGIONS, TEST_UTIL.getHBaseCluster().getRegions(tableName).size());
366 assertTrue("Table should be created with splitKyes + 1 rows in META",
367 admin.isTableAvailable(tableName).get());
369 // Clone & Verify
370 admin.cloneTableSchema(tableName, newTableName, preserveSplits).join();
371 TableDescriptor newTableDesc = admin.getDescriptor(newTableName).get();
373 assertEquals(NUM_FAMILYS, newTableDesc.getColumnFamilyCount());
374 assertEquals(BLOCK_SIZE, newTableDesc.getColumnFamily(FAMILY_1).getBlocksize());
375 assertEquals(BLOCK_CACHE, newTableDesc.getColumnFamily(FAMILY_1).isBlockCacheEnabled());
376 assertEquals(TTL, newTableDesc.getColumnFamily(FAMILY_1).getTimeToLive());
377 //HBASE-26246 introduced persist of store file tracker into table descriptor
378 tableDesc = TableDescriptorBuilder.newBuilder(tableDesc).setValue(TRACKER_IMPL,
379 StoreFileTrackerFactory.getStoreFileTrackerName(TEST_UTIL.getConfiguration())).
380 build();
381 TEST_UTIL.verifyTableDescriptorIgnoreTableName(tableDesc, newTableDesc);
383 if (preserveSplits) {
384 assertEquals(NUM_REGIONS, TEST_UTIL.getHBaseCluster().getRegions(newTableName).size());
385 assertTrue("New table should be created with splitKyes + 1 rows in META",
386 admin.isTableAvailable(newTableName).get());
387 } else {
388 assertEquals(1, TEST_UTIL.getHBaseCluster().getRegions(newTableName).size());
392 @Test
393 public void testCloneTableSchemaWithNonExistentSourceTable() throws Exception {
394 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new");
395 // test for non-existent source table
396 try {
397 admin.cloneTableSchema(tableName, newTableName, false).join();
398 fail("Should have failed when source table doesn't exist.");
399 } catch (CompletionException e) {
400 assertTrue(e.getCause() instanceof TableNotFoundException);
404 @Test
405 public void testCloneTableSchemaWithExistentDestinationTable() throws Exception {
406 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new");
407 byte[] FAMILY_0 = Bytes.toBytes("cf0");
408 TEST_UTIL.createTable(tableName, FAMILY_0);
409 TEST_UTIL.createTable(newTableName, FAMILY_0);
410 // test for existent destination table
411 try {
412 admin.cloneTableSchema(tableName, newTableName, false).join();
413 fail("Should have failed when destination table exists.");
414 } catch (CompletionException e) {
415 assertTrue(e.getCause() instanceof TableExistsException);
419 @Test
420 public void testIsTableAvailableWithInexistantTable() throws Exception {
421 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new");
422 // test for inexistant table
423 assertFalse(admin.isTableAvailable(newTableName).get());