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
;
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
{
59 public static final HBaseClassTestRule CLASS_RULE
=
60 HBaseClassTestRule
.forClass(TestAsyncTableAdminApi
.class);
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();
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
));
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());
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();
137 "Tried to create " + expectedRegions
+ " regions " + "but only found " + regions
.size(),
138 expectedRegions
, regions
.size());
139 System
.err
.println("Found " + regions
.size() + " regions");
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();
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 };
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
)
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");
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
);
256 public void testCreateTableWithOnlyEmptyStartRow() throws Exception
{
257 byte[][] splitKeys
= new byte[1][];
258 splitKeys
[0] = HConstants
.EMPTY_BYTE_ARRAY
;
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
);
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");
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
);
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());
291 public void testTruncateTable() throws Exception
{
292 testTruncateTable(tableName
, false);
296 public void testTruncateTablePreservingSplits() throws Exception
{
297 testTruncateTable(tableName
, true);
300 private void testTruncateTable(final TableName tableName
, boolean preserveSplits
)
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());
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());
326 assertEquals(1, TEST_UTIL
.getHBaseCluster().getRegions(tableName
).size());
331 public void testCloneTableSchema() throws Exception
{
332 final TableName newTableName
= TableName
.valueOf(tableName
.getNameAsString() + "_new");
333 testCloneTableSchema(tableName
, newTableName
, false);
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);
349 int BLOCK_SIZE
= 1024;
351 boolean BLOCK_CACHE
= false;
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
)
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());
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())).
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());
388 assertEquals(1, TEST_UTIL
.getHBaseCluster().getRegions(newTableName
).size());
393 public void testCloneTableSchemaWithNonExistentSourceTable() throws Exception
{
394 final TableName newTableName
= TableName
.valueOf(tableName
.getNameAsString() + "_new");
395 // test for non-existent source table
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
);
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
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
);
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());