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
.regionserver
.storefiletracker
.StoreFileTrackerFactory
.TRACKER_IMPL
;
21 import static org
.junit
.Assert
.assertArrayEquals
;
22 import static org
.junit
.Assert
.assertEquals
;
23 import static org
.junit
.Assert
.assertFalse
;
24 import static org
.junit
.Assert
.assertNull
;
25 import static org
.junit
.Assert
.assertThrows
;
26 import static org
.junit
.Assert
.assertTrue
;
27 import static org
.junit
.Assert
.fail
;
29 import java
.io
.IOException
;
30 import java
.util
.List
;
31 import java
.util
.regex
.Pattern
;
32 import org
.apache
.hadoop
.hbase
.DoNotRetryIOException
;
33 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
34 import org
.apache
.hadoop
.hbase
.HConstants
;
35 import org
.apache
.hadoop
.hbase
.HRegionLocation
;
36 import org
.apache
.hadoop
.hbase
.InvalidFamilyOperationException
;
37 import org
.apache
.hadoop
.hbase
.MetaTableAccessor
;
38 import org
.apache
.hadoop
.hbase
.TableName
;
39 import org
.apache
.hadoop
.hbase
.TableNotDisabledException
;
40 import org
.apache
.hadoop
.hbase
.TableNotEnabledException
;
41 import org
.apache
.hadoop
.hbase
.TableNotFoundException
;
42 import org
.apache
.hadoop
.hbase
.regionserver
.NoSuchColumnFamilyException
;
43 import org
.apache
.hadoop
.hbase
.regionserver
.storefiletracker
.StoreFileTrackerFactory
;
44 import org
.apache
.hadoop
.hbase
.testclassification
.ClientTests
;
45 import org
.apache
.hadoop
.hbase
.testclassification
.LargeTests
;
46 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
47 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManager
;
48 import org
.junit
.ClassRule
;
49 import org
.junit
.Test
;
50 import org
.junit
.experimental
.categories
.Category
;
51 import org
.slf4j
.Logger
;
52 import org
.slf4j
.LoggerFactory
;
54 @Category({ LargeTests
.class, ClientTests
.class })
55 public class TestAdmin3
extends TestAdminBase
{
58 public static final HBaseClassTestRule CLASS_RULE
= HBaseClassTestRule
.forClass(TestAdmin3
.class);
60 private static final Logger LOG
= LoggerFactory
.getLogger(TestAdmin3
.class);
63 public void testDisableAndEnableTable() throws IOException
{
64 final byte[] row
= Bytes
.toBytes("row");
65 final byte[] qualifier
= Bytes
.toBytes("qualifier");
66 final byte[] value
= Bytes
.toBytes("value");
67 final TableName table
= TableName
.valueOf(name
.getMethodName());
68 Table ht
= TEST_UTIL
.createTable(table
, HConstants
.CATALOG_FAMILY
);
69 Put put
= new Put(row
);
70 put
.addColumn(HConstants
.CATALOG_FAMILY
, qualifier
, value
);
72 Get get
= new Get(row
);
73 get
.addColumn(HConstants
.CATALOG_FAMILY
, qualifier
);
76 ADMIN
.disableTable(ht
.getName());
77 assertTrue("Table must be disabled.", TEST_UTIL
.getHBaseCluster().getMaster()
78 .getTableStateManager().isTableState(ht
.getName(), TableState
.State
.DISABLED
));
79 assertEquals(TableState
.State
.DISABLED
, getStateFromMeta(table
));
81 // Test that table is disabled
83 get
.addColumn(HConstants
.CATALOG_FAMILY
, qualifier
);
87 } catch (TableNotEnabledException e
) {
91 // verify that scan encounters correct exception
92 Scan scan
= new Scan();
94 ResultScanner scanner
= ht
.getScanner(scan
);
98 } while (res
!= null);
99 } catch (TableNotEnabledException e
) {
103 ADMIN
.enableTable(table
);
104 assertTrue("Table must be enabled.", TEST_UTIL
.getHBaseCluster().getMaster()
105 .getTableStateManager().isTableState(ht
.getName(), TableState
.State
.ENABLED
));
106 assertEquals(TableState
.State
.ENABLED
, getStateFromMeta(table
));
108 // Test that table is enabled
111 } catch (RetriesExhaustedException e
) {
119 public void testDisableAndEnableTables() throws IOException
{
120 final byte[] row
= Bytes
.toBytes("row");
121 final byte[] qualifier
= Bytes
.toBytes("qualifier");
122 final byte[] value
= Bytes
.toBytes("value");
123 final TableName table1
= TableName
.valueOf(name
.getMethodName() + "1");
124 final TableName table2
= TableName
.valueOf(name
.getMethodName() + "2");
125 Table ht1
= TEST_UTIL
.createTable(table1
, HConstants
.CATALOG_FAMILY
);
126 Table ht2
= TEST_UTIL
.createTable(table2
, HConstants
.CATALOG_FAMILY
);
127 Put put
= new Put(row
);
128 put
.addColumn(HConstants
.CATALOG_FAMILY
, qualifier
, value
);
131 Get get
= new Get(row
);
132 get
.addColumn(HConstants
.CATALOG_FAMILY
, qualifier
);
136 TableName
[] tableNames
= ADMIN
.listTableNames(Pattern
.compile("testDisableAndEnableTable.*"));
137 for (TableName tableName
: tableNames
) {
138 ADMIN
.disableTable(tableName
);
141 // Test that tables are disabled
143 get
.addColumn(HConstants
.CATALOG_FAMILY
, qualifier
);
148 } catch (org
.apache
.hadoop
.hbase
.DoNotRetryIOException e
) {
152 assertEquals(TableState
.State
.DISABLED
, getStateFromMeta(table1
));
153 assertEquals(TableState
.State
.DISABLED
, getStateFromMeta(table2
));
156 for (TableName tableName
: tableNames
) {
157 ADMIN
.enableTable(tableName
);
160 // Test that tables are enabled
163 } catch (IOException e
) {
168 } catch (IOException e
) {
176 assertEquals(TableState
.State
.ENABLED
, getStateFromMeta(table1
));
177 assertEquals(TableState
.State
.ENABLED
, getStateFromMeta(table2
));
181 * Test retain assignment on enableTable.
184 public void testEnableTableRetainAssignment() throws IOException
{
185 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
186 byte[][] splitKeys
= { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, new byte[] { 3, 3, 3 },
187 new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 }, new byte[] { 6, 6, 6 },
188 new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 }, new byte[] { 9, 9, 9 } };
189 int expectedRegions
= splitKeys
.length
+ 1;
190 TableDescriptor desc
= TableDescriptorBuilder
.newBuilder(tableName
)
191 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of(HConstants
.CATALOG_FAMILY
)).build();
192 ADMIN
.createTable(desc
, splitKeys
);
194 try (RegionLocator l
= TEST_UTIL
.getConnection().getRegionLocator(tableName
)) {
195 List
<HRegionLocation
> regions
= l
.getAllRegionLocations();
198 "Tried to create " + expectedRegions
+ " regions " + "but only found " + regions
.size(),
199 expectedRegions
, regions
.size());
201 ADMIN
.disableTable(tableName
);
202 // Enable table, use retain assignment to assign regions.
203 ADMIN
.enableTable(tableName
);
204 List
<HRegionLocation
> regions2
= l
.getAllRegionLocations();
206 // Check the assignment.
207 assertEquals(regions
.size(), regions2
.size());
208 assertTrue(regions2
.containsAll(regions
));
213 public void testEnableDisableAddColumnDeleteColumn() throws Exception
{
214 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
215 TEST_UTIL
.createTable(tableName
, HConstants
.CATALOG_FAMILY
).close();
216 while (!ADMIN
.isTableEnabled(TableName
.valueOf(name
.getMethodName()))) {
219 ADMIN
.disableTable(tableName
);
221 TEST_UTIL
.getConnection().getTable(tableName
);
222 } catch (org
.apache
.hadoop
.hbase
.DoNotRetryIOException e
) {
226 ADMIN
.addColumnFamily(tableName
, ColumnFamilyDescriptorBuilder
.of("col2"));
227 ADMIN
.enableTable(tableName
);
229 ADMIN
.deleteColumnFamily(tableName
, Bytes
.toBytes("col2"));
230 } catch (TableNotDisabledException e
) {
231 LOG
.info(e
.toString(), e
);
233 ADMIN
.disableTable(tableName
);
234 ADMIN
.deleteTable(tableName
);
238 public void testGetTableDescriptor() throws IOException
{
239 TableDescriptor htd
= TableDescriptorBuilder
.newBuilder(TableName
.valueOf(name
.getMethodName()))
240 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of("fam1"))
241 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of("fam2"))
242 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of("fam3")).build();
243 ADMIN
.createTable(htd
);
244 Table table
= TEST_UTIL
.getConnection().getTable(htd
.getTableName());
245 TableDescriptor confirmedHtd
= table
.getDescriptor();
246 //HBASE-26246 introduced persist of store file tracker into table descriptor
247 htd
= TableDescriptorBuilder
.newBuilder(htd
).setValue(TRACKER_IMPL
,
248 StoreFileTrackerFactory
.getStoreFileTrackerName(TEST_UTIL
.getConfiguration())).
250 assertEquals(0, TableDescriptor
.COMPARATOR
.compare(htd
, confirmedHtd
));
251 MetaTableAccessor
.fullScanMetaAndPrint(TEST_UTIL
.getConnection());
256 * Verify schema change for read only table
259 public void testReadOnlyTableModify() throws IOException
, InterruptedException
{
260 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
261 TEST_UTIL
.createTable(tableName
, HConstants
.CATALOG_FAMILY
).close();
263 // Make table read only
264 TableDescriptor htd
=
265 TableDescriptorBuilder
.newBuilder(ADMIN
.getDescriptor(tableName
)).setReadOnly(true).build();
266 ADMIN
.modifyTable(htd
);
268 // try to modify the read only table now
269 htd
= TableDescriptorBuilder
.newBuilder(ADMIN
.getDescriptor(tableName
))
270 .setCompactionEnabled(false).build();
271 ADMIN
.modifyTable(htd
);
273 ADMIN
.disableTable(tableName
);
274 ADMIN
.deleteTable(tableName
);
275 assertFalse(ADMIN
.tableExists(tableName
));
279 public void testDeleteLastColumnFamily() throws Exception
{
280 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
281 TEST_UTIL
.createTable(tableName
, HConstants
.CATALOG_FAMILY
).close();
282 while (!ADMIN
.isTableEnabled(TableName
.valueOf(name
.getMethodName()))) {
286 // test for enabled table
288 ADMIN
.deleteColumnFamily(tableName
, HConstants
.CATALOG_FAMILY
);
289 fail("Should have failed to delete the only column family of a table");
290 } catch (InvalidFamilyOperationException ex
) {
294 // test for disabled table
295 ADMIN
.disableTable(tableName
);
298 ADMIN
.deleteColumnFamily(tableName
, HConstants
.CATALOG_FAMILY
);
299 fail("Should have failed to delete the only column family of a table");
300 } catch (InvalidFamilyOperationException ex
) {
304 ADMIN
.deleteTable(tableName
);
308 public void testDeleteEditUnknownColumnFamilyAndOrTable() throws IOException
{
309 // Test we get exception if we try to
310 final TableName nonexistentTable
= TableName
.valueOf("nonexistent");
311 final byte[] nonexistentColumn
= Bytes
.toBytes("nonexistent");
312 ColumnFamilyDescriptor nonexistentHcd
= ColumnFamilyDescriptorBuilder
.of(nonexistentColumn
);
313 Exception exception
= null;
315 ADMIN
.addColumnFamily(nonexistentTable
, nonexistentHcd
);
316 } catch (IOException e
) {
319 assertTrue(exception
instanceof TableNotFoundException
);
323 ADMIN
.deleteTable(nonexistentTable
);
324 } catch (IOException e
) {
327 assertTrue(exception
instanceof TableNotFoundException
);
331 ADMIN
.deleteColumnFamily(nonexistentTable
, nonexistentColumn
);
332 } catch (IOException e
) {
335 assertTrue(exception
instanceof TableNotFoundException
);
339 ADMIN
.disableTable(nonexistentTable
);
340 } catch (IOException e
) {
343 assertTrue(exception
instanceof TableNotFoundException
);
347 ADMIN
.enableTable(nonexistentTable
);
348 } catch (IOException e
) {
351 assertTrue(exception
instanceof TableNotFoundException
);
355 ADMIN
.modifyColumnFamily(nonexistentTable
, nonexistentHcd
);
356 } catch (IOException e
) {
359 assertTrue(exception
instanceof TableNotFoundException
);
363 TableDescriptor htd
= TableDescriptorBuilder
.newBuilder(nonexistentTable
)
364 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of(HConstants
.CATALOG_FAMILY
)).build();
365 ADMIN
.modifyTable(htd
);
366 } catch (IOException e
) {
369 assertTrue(exception
instanceof TableNotFoundException
);
371 // Now make it so at least the table exists and then do tests against a
372 // nonexistent column family -- see if we get right exceptions.
373 final TableName tableName
=
374 TableName
.valueOf(name
.getMethodName() + EnvironmentEdgeManager
.currentTime());
375 TableDescriptor htd
= TableDescriptorBuilder
.newBuilder(tableName
)
376 .setColumnFamily(ColumnFamilyDescriptorBuilder
.of("cf")).build();
377 ADMIN
.createTable(htd
);
381 ADMIN
.deleteColumnFamily(htd
.getTableName(), nonexistentHcd
.getName());
382 } catch (IOException e
) {
385 assertTrue("found=" + exception
.getClass().getName(),
386 exception
instanceof InvalidFamilyOperationException
);
390 ADMIN
.modifyColumnFamily(htd
.getTableName(), nonexistentHcd
);
391 } catch (IOException e
) {
394 assertTrue("found=" + exception
.getClass().getName(),
395 exception
instanceof InvalidFamilyOperationException
);
397 ADMIN
.disableTable(tableName
);
398 ADMIN
.deleteTable(tableName
);
402 private static final String SRC_IMPL
= "hbase.store.file-tracker.migration.src.impl";
404 private static final String DST_IMPL
= "hbase.store.file-tracker.migration.dst.impl";
406 private void verifyModifyTableResult(TableName tableName
, byte[] family
, byte[] qual
, byte[] row
,
407 byte[] value
, String sft
) throws IOException
{
408 TableDescriptor td
= ADMIN
.getDescriptor(tableName
);
409 assertEquals(sft
, td
.getValue(StoreFileTrackerFactory
.TRACKER_IMPL
));
410 // no migration related configs
411 assertNull(td
.getValue(SRC_IMPL
));
412 assertNull(td
.getValue(DST_IMPL
));
413 try (Table table
= TEST_UTIL
.getConnection().getTable(tableName
)) {
414 assertArrayEquals(value
, table
.get(new Get(row
)).getValue(family
, qual
));
419 public void testModifyTableStoreFileTracker() throws IOException
{
420 TableName tableName
= TableName
.valueOf(name
.getMethodName());
421 byte[] family
= Bytes
.toBytes("info");
422 byte[] qual
= Bytes
.toBytes("q");
423 byte[] row
= Bytes
.toBytes(0);
424 byte[] value
= Bytes
.toBytes(1);
425 try (Table table
= TEST_UTIL
.createTable(tableName
, family
)) {
426 table
.put(new Put(row
).addColumn(family
, qual
, value
));
429 ADMIN
.modifyTableStoreFileTracker(tableName
, StoreFileTrackerFactory
.Trackers
.FILE
.name());
430 verifyModifyTableResult(tableName
, family
, qual
, row
, value
,
431 StoreFileTrackerFactory
.Trackers
.FILE
.name());
433 // change to FILE again, should have no effect
434 ADMIN
.modifyTableStoreFileTracker(tableName
, StoreFileTrackerFactory
.Trackers
.FILE
.name());
435 verifyModifyTableResult(tableName
, family
, qual
, row
, value
,
436 StoreFileTrackerFactory
.Trackers
.FILE
.name());
438 // change to MIGRATION, and then to FILE
439 ADMIN
.modifyTable(TableDescriptorBuilder
.newBuilder(ADMIN
.getDescriptor(tableName
))
440 .setValue(StoreFileTrackerFactory
.TRACKER_IMPL
,
441 StoreFileTrackerFactory
.Trackers
.MIGRATION
.name())
443 StoreFileTrackerFactory
.Trackers
.FILE
.name())
445 StoreFileTrackerFactory
.Trackers
.DEFAULT
.name())
447 ADMIN
.modifyTableStoreFileTracker(tableName
, StoreFileTrackerFactory
.Trackers
.FILE
.name());
448 verifyModifyTableResult(tableName
, family
, qual
, row
, value
,
449 StoreFileTrackerFactory
.Trackers
.FILE
.name());
451 // change to MIGRATION, and then to DEFAULT
452 ADMIN
.modifyTable(TableDescriptorBuilder
.newBuilder(ADMIN
.getDescriptor(tableName
))
453 .setValue(StoreFileTrackerFactory
.TRACKER_IMPL
,
454 StoreFileTrackerFactory
.Trackers
.MIGRATION
.name())
456 StoreFileTrackerFactory
.Trackers
.FILE
.name())
458 StoreFileTrackerFactory
.Trackers
.DEFAULT
.name())
460 ADMIN
.modifyTableStoreFileTracker(tableName
, StoreFileTrackerFactory
.Trackers
.DEFAULT
.name());
461 verifyModifyTableResult(tableName
, family
, qual
, row
, value
,
462 StoreFileTrackerFactory
.Trackers
.DEFAULT
.name());
465 private void verifyModifyColumnFamilyResult(TableName tableName
, byte[] family
, byte[] qual
,
466 byte[] row
, byte[] value
, String sft
) throws IOException
{
467 TableDescriptor td
= ADMIN
.getDescriptor(tableName
);
468 ColumnFamilyDescriptor cfd
= td
.getColumnFamily(family
);
469 assertEquals(sft
, cfd
.getConfigurationValue(StoreFileTrackerFactory
.TRACKER_IMPL
));
470 // no migration related configs
471 assertNull(cfd
.getConfigurationValue(SRC_IMPL
));
472 assertNull(cfd
.getConfigurationValue(DST_IMPL
));
473 assertNull(cfd
.getValue(SRC_IMPL
));
474 assertNull(cfd
.getValue(DST_IMPL
));
475 try (Table table
= TEST_UTIL
.getConnection().getTable(tableName
)) {
476 assertArrayEquals(value
, table
.get(new Get(row
)).getValue(family
, qual
));
481 public void testModifyColumnFamilyStoreFileTracker() throws IOException
{
482 TableName tableName
= TableName
.valueOf(name
.getMethodName());
483 byte[] family
= Bytes
.toBytes("info");
484 byte[] qual
= Bytes
.toBytes("q");
485 byte[] row
= Bytes
.toBytes(0);
486 byte[] value
= Bytes
.toBytes(1);
487 try (Table table
= TEST_UTIL
.createTable(tableName
, family
)) {
488 table
.put(new Put(row
).addColumn(family
, qual
, value
));
491 ADMIN
.modifyColumnFamilyStoreFileTracker(tableName
, family
,
492 StoreFileTrackerFactory
.Trackers
.FILE
.name());
493 verifyModifyColumnFamilyResult(tableName
, family
, qual
, row
, value
,
494 StoreFileTrackerFactory
.Trackers
.FILE
.name());
496 // change to FILE again, should have no effect
497 ADMIN
.modifyColumnFamilyStoreFileTracker(tableName
, family
,
498 StoreFileTrackerFactory
.Trackers
.FILE
.name());
499 verifyModifyColumnFamilyResult(tableName
, family
, qual
, row
, value
,
500 StoreFileTrackerFactory
.Trackers
.FILE
.name());
502 // change to MIGRATION, and then to FILE
503 TableDescriptor current
= ADMIN
.getDescriptor(tableName
);
504 ADMIN
.modifyTable(TableDescriptorBuilder
.newBuilder(current
)
505 .modifyColumnFamily(ColumnFamilyDescriptorBuilder
.newBuilder(current
.getColumnFamily(family
))
506 .setConfiguration(StoreFileTrackerFactory
.TRACKER_IMPL
,
507 StoreFileTrackerFactory
.Trackers
.MIGRATION
.name())
508 .setConfiguration(SRC_IMPL
, StoreFileTrackerFactory
.Trackers
.FILE
.name())
509 .setConfiguration(DST_IMPL
, StoreFileTrackerFactory
.Trackers
.DEFAULT
.name()).build())
511 ADMIN
.modifyColumnFamilyStoreFileTracker(tableName
, family
,
512 StoreFileTrackerFactory
.Trackers
.FILE
.name());
513 verifyModifyColumnFamilyResult(tableName
, family
, qual
, row
, value
,
514 StoreFileTrackerFactory
.Trackers
.FILE
.name());
516 // change to MIGRATION, and then to DEFAULT
517 current
= ADMIN
.getDescriptor(tableName
);
518 ADMIN
.modifyTable(TableDescriptorBuilder
.newBuilder(current
)
519 .modifyColumnFamily(ColumnFamilyDescriptorBuilder
.newBuilder(current
.getColumnFamily(family
))
520 .setConfiguration(StoreFileTrackerFactory
.TRACKER_IMPL
,
521 StoreFileTrackerFactory
.Trackers
.MIGRATION
.name())
522 .setConfiguration(SRC_IMPL
, StoreFileTrackerFactory
.Trackers
.FILE
.name())
523 .setConfiguration(DST_IMPL
, StoreFileTrackerFactory
.Trackers
.DEFAULT
.name()).build())
525 ADMIN
.modifyColumnFamilyStoreFileTracker(tableName
, family
,
526 StoreFileTrackerFactory
.Trackers
.DEFAULT
.name());
527 verifyModifyColumnFamilyResult(tableName
, family
, qual
, row
, value
,
528 StoreFileTrackerFactory
.Trackers
.DEFAULT
.name());
532 public void testModifyStoreFileTrackerError() throws IOException
{
533 TableName tableName
= TableName
.valueOf(name
.getMethodName());
534 byte[] family
= Bytes
.toBytes("info");
535 TEST_UTIL
.createTable(tableName
, family
).close();
538 assertThrows(TableNotFoundException
.class,
539 () -> ADMIN
.modifyTableStoreFileTracker(TableName
.valueOf("whatever"),
540 StoreFileTrackerFactory
.Trackers
.FILE
.name()));
542 assertThrows(NoSuchColumnFamilyException
.class,
543 () -> ADMIN
.modifyColumnFamilyStoreFileTracker(tableName
, Bytes
.toBytes("not_exists"),
544 StoreFileTrackerFactory
.Trackers
.FILE
.name()));
546 assertThrows(DoNotRetryIOException
.class, () -> ADMIN
.modifyTableStoreFileTracker(tableName
,
547 StoreFileTrackerFactory
.Trackers
.MIGRATION
.name()));
549 ADMIN
.disableTable(tableName
);
550 assertThrows(TableNotEnabledException
.class, () -> ADMIN
.modifyTableStoreFileTracker(tableName
,
551 StoreFileTrackerFactory
.Trackers
.FILE
.name()));