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 static org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory.TRACKER_IMPL; 021import static org.junit.Assert.assertEquals; 022import static org.junit.Assert.assertFalse; 023import static org.junit.Assert.assertNotEquals; 024import static org.junit.Assert.assertNotNull; 025import static org.junit.Assert.assertNull; 026import static org.junit.Assert.assertTrue; 027import static org.junit.Assert.fail; 028 029import java.io.IOException; 030import java.util.ArrayList; 031import java.util.HashMap; 032import java.util.Iterator; 033import java.util.List; 034import java.util.Map; 035import org.apache.hadoop.hbase.HBaseClassTestRule; 036import org.apache.hadoop.hbase.HConstants; 037import org.apache.hadoop.hbase.HRegionLocation; 038import org.apache.hadoop.hbase.ServerName; 039import org.apache.hadoop.hbase.TableExistsException; 040import org.apache.hadoop.hbase.TableName; 041import org.apache.hadoop.hbase.TableNotFoundException; 042import org.apache.hadoop.hbase.master.LoadBalancer; 043import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory; 044import org.apache.hadoop.hbase.testclassification.ClientTests; 045import org.apache.hadoop.hbase.testclassification.LargeTests; 046import org.apache.hadoop.hbase.util.Bytes; 047import org.junit.ClassRule; 048import org.junit.Test; 049import org.junit.experimental.categories.Category; 050import org.slf4j.Logger; 051import org.slf4j.LoggerFactory; 052 053@Category({ LargeTests.class, ClientTests.class }) 054public class TestAdmin extends TestAdminBase { 055 056 @ClassRule 057 public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestAdmin.class); 058 059 private static final Logger LOG = LoggerFactory.getLogger(TestAdmin.class); 060 061 @Test 062 public void testCreateTable() throws IOException { 063 List<TableDescriptor> tables = ADMIN.listTableDescriptors(); 064 int numTables = tables.size(); 065 final TableName tableName = TableName.valueOf(name.getMethodName()); 066 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); 067 tables = ADMIN.listTableDescriptors(); 068 assertEquals(numTables + 1, tables.size()); 069 assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster().getMaster() 070 .getTableStateManager().isTableState(tableName, TableState.State.ENABLED)); 071 assertEquals(TableState.State.ENABLED, getStateFromMeta(tableName)); 072 } 073 074 @Test 075 public void testTruncateTable() throws IOException { 076 testTruncateTable(TableName.valueOf(name.getMethodName()), false); 077 } 078 079 @Test 080 public void testTruncateTablePreservingSplits() throws IOException { 081 testTruncateTable(TableName.valueOf(name.getMethodName()), true); 082 } 083 084 private void testTruncateTable(final TableName tableName, boolean preserveSplits) 085 throws IOException { 086 byte[][] splitKeys = new byte[2][]; 087 splitKeys[0] = Bytes.toBytes(4); 088 splitKeys[1] = Bytes.toBytes(8); 089 090 // Create & Fill the table 091 Table table = TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY, splitKeys); 092 try { 093 TEST_UTIL.loadNumericRows(table, HConstants.CATALOG_FAMILY, 0, 10); 094 assertEquals(10, TEST_UTIL.countRows(table)); 095 } finally { 096 table.close(); 097 } 098 assertEquals(3, TEST_UTIL.getHBaseCluster().getRegions(tableName).size()); 099 100 // Truncate & Verify 101 ADMIN.disableTable(tableName); 102 ADMIN.truncateTable(tableName, preserveSplits); 103 table = TEST_UTIL.getConnection().getTable(tableName); 104 try { 105 assertEquals(0, TEST_UTIL.countRows(table)); 106 } finally { 107 table.close(); 108 } 109 if (preserveSplits) { 110 assertEquals(3, TEST_UTIL.getHBaseCluster().getRegions(tableName).size()); 111 } else { 112 assertEquals(1, TEST_UTIL.getHBaseCluster().getRegions(tableName).size()); 113 } 114 } 115 116 @Test 117 public void testCreateTableNumberOfRegions() throws IOException, InterruptedException { 118 TableName table = TableName.valueOf(name.getMethodName()); 119 ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder.of(HConstants.CATALOG_FAMILY); 120 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table).setColumnFamily(cfd).build()); 121 List<HRegionLocation> regions; 122 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(table)) { 123 regions = l.getAllRegionLocations(); 124 assertEquals("Table should have only 1 region", 1, regions.size()); 125 } 126 127 TableName table2 = TableName.valueOf(table.getNameAsString() + "_2"); 128 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table2).setColumnFamily(cfd).build(), 129 new byte[][] { new byte[] { 42 } }); 130 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(table2)) { 131 regions = l.getAllRegionLocations(); 132 assertEquals("Table should have only 2 region", 2, regions.size()); 133 } 134 135 TableName table3 = TableName.valueOf(table.getNameAsString() + "_3"); 136 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table3).setColumnFamily(cfd).build(), 137 Bytes.toBytes("a"), Bytes.toBytes("z"), 3); 138 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(table3)) { 139 regions = l.getAllRegionLocations(); 140 assertEquals("Table should have only 3 region", 3, regions.size()); 141 } 142 143 TableName table4 = TableName.valueOf(table.getNameAsString() + "_4"); 144 try { 145 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table4).setColumnFamily(cfd).build(), 146 Bytes.toBytes("a"), Bytes.toBytes("z"), 2); 147 fail("Should not be able to create a table with only 2 regions using this API."); 148 } catch (IllegalArgumentException eae) { 149 // Expected 150 } 151 152 TableName table5 = TableName.valueOf(table.getNameAsString() + "_5"); 153 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table5).setColumnFamily(cfd).build(), 154 new byte[] { 1 }, new byte[] { 127 }, 16); 155 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(table5)) { 156 regions = l.getAllRegionLocations(); 157 assertEquals("Table should have 16 region", 16, regions.size()); 158 } 159 } 160 161 @Test 162 public void testCreateTableWithRegions() throws IOException, InterruptedException { 163 TableName table = TableName.valueOf(name.getMethodName()); 164 ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder.of(HConstants.CATALOG_FAMILY); 165 byte[][] splitKeys = { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, new byte[] { 3, 3, 3 }, 166 new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 }, new byte[] { 6, 6, 6 }, 167 new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 }, new byte[] { 9, 9, 9 }, }; 168 int expectedRegions = splitKeys.length + 1; 169 170 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table).setColumnFamily(cfd).build(), 171 splitKeys); 172 173 boolean tableAvailable = ADMIN.isTableAvailable(table); 174 assertTrue("Table should be created with splitKyes + 1 rows in META", tableAvailable); 175 176 List<HRegionLocation> regions; 177 Iterator<HRegionLocation> hris; 178 RegionInfo hri; 179 ClusterConnection conn = (ClusterConnection) TEST_UTIL.getConnection(); 180 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(table)) { 181 regions = l.getAllRegionLocations(); 182 183 assertEquals( 184 "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(), 185 expectedRegions, regions.size()); 186 System.err.println("Found " + regions.size() + " regions"); 187 188 hris = regions.iterator(); 189 hri = hris.next().getRegion(); 190 assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0); 191 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[0])); 192 hri = hris.next().getRegion(); 193 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[0])); 194 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[1])); 195 hri = hris.next().getRegion(); 196 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[1])); 197 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[2])); 198 hri = hris.next().getRegion(); 199 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[2])); 200 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[3])); 201 hri = hris.next().getRegion(); 202 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[3])); 203 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[4])); 204 hri = hris.next().getRegion(); 205 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[4])); 206 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[5])); 207 hri = hris.next().getRegion(); 208 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[5])); 209 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[6])); 210 hri = hris.next().getRegion(); 211 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[6])); 212 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[7])); 213 hri = hris.next().getRegion(); 214 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[7])); 215 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[8])); 216 hri = hris.next().getRegion(); 217 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[8])); 218 assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0); 219 220 verifyRoundRobinDistribution(l, expectedRegions); 221 } 222 223 // Now test using start/end with a number of regions 224 225 // Use 80 bit numbers to make sure we aren't limited 226 byte[] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 227 byte[] endKey = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; 228 229 // Splitting into 10 regions, we expect (null,1) ... (9, null) 230 // with (1,2) (2,3) (3,4) (4,5) (5,6) (6,7) (7,8) (8,9) in the middle 231 232 expectedRegions = 10; 233 234 TableName table2 = TableName.valueOf(table.getNameAsString() + "_2"); 235 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table2).setColumnFamily(cfd).build(), 236 startKey, endKey, expectedRegions); 237 238 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(table2)) { 239 regions = l.getAllRegionLocations(); 240 assertEquals( 241 "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(), 242 expectedRegions, regions.size()); 243 System.err.println("Found " + regions.size() + " regions"); 244 245 hris = regions.iterator(); 246 hri = hris.next().getRegion(); 247 assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0); 248 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 })); 249 hri = hris.next().getRegion(); 250 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 })); 251 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 })); 252 hri = hris.next().getRegion(); 253 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 })); 254 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 })); 255 hri = hris.next().getRegion(); 256 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 })); 257 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 })); 258 hri = hris.next().getRegion(); 259 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 })); 260 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 })); 261 hri = hris.next().getRegion(); 262 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 })); 263 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 })); 264 hri = hris.next().getRegion(); 265 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 })); 266 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 })); 267 hri = hris.next().getRegion(); 268 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 })); 269 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 })); 270 hri = hris.next().getRegion(); 271 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 })); 272 assertTrue(Bytes.equals(hri.getEndKey(), new byte[] { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 })); 273 hri = hris.next().getRegion(); 274 assertTrue(Bytes.equals(hri.getStartKey(), new byte[] { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 })); 275 assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0); 276 277 verifyRoundRobinDistribution(l, expectedRegions); 278 } 279 280 // Try once more with something that divides into something infinite 281 282 startKey = new byte[] { 0, 0, 0, 0, 0, 0 }; 283 endKey = new byte[] { 1, 0, 0, 0, 0, 0 }; 284 285 expectedRegions = 5; 286 287 TableName table3 = TableName.valueOf(table.getNameAsString() + "_3"); 288 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table3).setColumnFamily(cfd).build(), 289 startKey, endKey, expectedRegions); 290 291 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(table3)) { 292 regions = l.getAllRegionLocations(); 293 assertEquals( 294 "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(), 295 expectedRegions, regions.size()); 296 System.err.println("Found " + regions.size() + " regions"); 297 298 verifyRoundRobinDistribution(l, expectedRegions); 299 } 300 301 // Try an invalid case where there are duplicate split keys 302 splitKeys = new byte[][] { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, 303 new byte[] { 3, 3, 3 }, new byte[] { 2, 2, 2 } }; 304 305 TableName table4 = TableName.valueOf(table.getNameAsString() + "_4"); 306 try { 307 ADMIN.createTable(TableDescriptorBuilder.newBuilder(table4).setColumnFamily(cfd).build(), 308 splitKeys); 309 assertTrue("Should not be able to create this table because of " + "duplicate split keys", 310 false); 311 } catch (IllegalArgumentException iae) { 312 // Expected 313 } 314 } 315 316 @Test 317 public void testCreateTableWithOnlyEmptyStartRow() throws IOException { 318 final byte[] tableName = Bytes.toBytes(name.getMethodName()); 319 byte[][] splitKeys = new byte[1][]; 320 splitKeys[0] = HConstants.EMPTY_BYTE_ARRAY; 321 TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName)) 322 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("col")).build(); 323 try { 324 ADMIN.createTable(desc, splitKeys); 325 fail("Test case should fail as empty split key is passed."); 326 } catch (IllegalArgumentException e) { 327 } 328 } 329 330 @Test 331 public void testCreateTableWithEmptyRowInTheSplitKeys() throws IOException { 332 final byte[] tableName = Bytes.toBytes(name.getMethodName()); 333 byte[][] splitKeys = new byte[3][]; 334 splitKeys[0] = Bytes.toBytes("region1"); 335 splitKeys[1] = HConstants.EMPTY_BYTE_ARRAY; 336 splitKeys[2] = Bytes.toBytes("region2"); 337 TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName)) 338 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("col")).build(); 339 try { 340 ADMIN.createTable(desc, splitKeys); 341 fail("Test case should fail as empty split key is passed."); 342 } catch (IllegalArgumentException e) { 343 LOG.info("Expected ", e); 344 } 345 } 346 347 private void verifyRoundRobinDistribution(RegionLocator regionLocator, int expectedRegions) 348 throws IOException { 349 int numRS = TEST_UTIL.getMiniHBaseCluster().getNumLiveRegionServers(); 350 List<HRegionLocation> regions = regionLocator.getAllRegionLocations(); 351 Map<ServerName, List<RegionInfo>> server2Regions = new HashMap<>(); 352 for (HRegionLocation loc : regions) { 353 ServerName server = loc.getServerName(); 354 List<RegionInfo> regs = server2Regions.get(server); 355 if (regs == null) { 356 regs = new ArrayList<>(); 357 server2Regions.put(server, regs); 358 } 359 regs.add(loc.getRegion()); 360 } 361 boolean tablesOnMaster = LoadBalancer.isTablesOnMaster(TEST_UTIL.getConfiguration()); 362 if (tablesOnMaster) { 363 // Ignore the master region server, 364 // which contains less regions by intention. 365 numRS--; 366 } 367 float average = (float) expectedRegions / numRS; 368 int min = (int) Math.floor(average); 369 int max = (int) Math.ceil(average); 370 for (List<RegionInfo> regionList : server2Regions.values()) { 371 assertTrue( 372 "numRS=" + numRS + ", min=" + min + ", max=" + max + ", size=" + regionList.size() 373 + ", tablesOnMaster=" + tablesOnMaster, 374 regionList.size() == min || regionList.size() == max); 375 } 376 } 377 378 @Test 379 public void testCloneTableSchema() throws Exception { 380 final TableName tableName = TableName.valueOf(name.getMethodName()); 381 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new"); 382 testCloneTableSchema(tableName, newTableName, false); 383 } 384 385 @Test 386 public void testCloneTableSchemaPreservingSplits() throws Exception { 387 final TableName tableName = TableName.valueOf(name.getMethodName()); 388 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new"); 389 testCloneTableSchema(tableName, newTableName, true); 390 } 391 392 private void testCloneTableSchema(final TableName tableName, final TableName newTableName, 393 boolean preserveSplits) throws Exception { 394 byte[] FAMILY_0 = Bytes.toBytes("cf0"); 395 byte[] FAMILY_1 = Bytes.toBytes("cf1"); 396 byte[][] splitKeys = new byte[2][]; 397 splitKeys[0] = Bytes.toBytes(4); 398 splitKeys[1] = Bytes.toBytes(8); 399 int NUM_FAMILYS = 2; 400 int NUM_REGIONS = 3; 401 int BLOCK_SIZE = 1024; 402 int TTL = 86400; 403 boolean BLOCK_CACHE = false; 404 405 // Create the table 406 TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(tableName) 407 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_0)) 408 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILY_1).setBlocksize(BLOCK_SIZE) 409 .setBlockCacheEnabled(BLOCK_CACHE).setTimeToLive(TTL).build()) 410 .build(); 411 ADMIN.createTable(tableDesc, splitKeys); 412 413 assertEquals(NUM_REGIONS, TEST_UTIL.getHBaseCluster().getRegions(tableName).size()); 414 assertTrue("Table should be created with splitKyes + 1 rows in META", 415 ADMIN.isTableAvailable(tableName)); 416 417 // clone & Verify 418 ADMIN.cloneTableSchema(tableName, newTableName, preserveSplits); 419 TableDescriptor newTableDesc = ADMIN.getDescriptor(newTableName); 420 421 assertEquals(NUM_FAMILYS, newTableDesc.getColumnFamilyCount()); 422 assertEquals(BLOCK_SIZE, newTableDesc.getColumnFamily(FAMILY_1).getBlocksize()); 423 assertEquals(BLOCK_CACHE, newTableDesc.getColumnFamily(FAMILY_1).isBlockCacheEnabled()); 424 assertEquals(TTL, newTableDesc.getColumnFamily(FAMILY_1).getTimeToLive()); 425 // HBASE-26246 introduced persist of store file tracker into table descriptor 426 tableDesc = TableDescriptorBuilder.newBuilder(tableDesc).setValue(TRACKER_IMPL, 427 StoreFileTrackerFactory.getStoreFileTrackerName(TEST_UTIL.getConfiguration())).build(); 428 TEST_UTIL.verifyTableDescriptorIgnoreTableName(tableDesc, newTableDesc); 429 430 if (preserveSplits) { 431 assertEquals(NUM_REGIONS, TEST_UTIL.getHBaseCluster().getRegions(newTableName).size()); 432 assertTrue("New table should be created with splitKyes + 1 rows in META", 433 ADMIN.isTableAvailable(newTableName)); 434 } else { 435 assertEquals(1, TEST_UTIL.getHBaseCluster().getRegions(newTableName).size()); 436 } 437 } 438 439 @Test 440 public void testCloneTableSchemaWithNonExistentSourceTable() throws Exception { 441 final TableName tableName = TableName.valueOf(name.getMethodName()); 442 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new"); 443 // test for non-existent source table 444 try { 445 ADMIN.cloneTableSchema(tableName, newTableName, false); 446 fail("Should have failed to create a new table by cloning non-existent source table."); 447 } catch (TableNotFoundException ex) { 448 // expected 449 } 450 } 451 452 @Test 453 public void testCloneTableSchemaWithExistentDestinationTable() throws Exception { 454 final TableName tableName = TableName.valueOf(name.getMethodName()); 455 final TableName newTableName = TableName.valueOf(tableName.getNameAsString() + "_new"); 456 byte[] FAMILY_0 = Bytes.toBytes("cf0"); 457 TEST_UTIL.createTable(tableName, FAMILY_0); 458 TEST_UTIL.createTable(newTableName, FAMILY_0); 459 // test for existent destination table 460 try { 461 ADMIN.cloneTableSchema(tableName, newTableName, false); 462 fail("Should have failed to create a existent table."); 463 } catch (TableExistsException ex) { 464 // expected 465 } 466 } 467 468 @Test 469 public void testModifyTableOnTableWithRegionReplicas() throws Exception { 470 TableName tableName = TableName.valueOf(name.getMethodName()); 471 TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName) 472 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(Bytes.toBytes("cf"))) 473 .setRegionReplication(5).build(); 474 475 ADMIN.createTable(desc); 476 477 int maxFileSize = 10000000; 478 TableDescriptor newDesc = 479 TableDescriptorBuilder.newBuilder(desc).setMaxFileSize(maxFileSize).build(); 480 481 ADMIN.modifyTable(newDesc); 482 TableDescriptor newTableDesc = ADMIN.getDescriptor(tableName); 483 assertEquals(maxFileSize, newTableDesc.getMaxFileSize()); 484 } 485 486 /** 487 * Verify schema modification takes. 488 */ 489 @Test 490 public void testOnlineChangeTableSchema() throws IOException, InterruptedException { 491 final TableName tableName = TableName.valueOf(name.getMethodName()); 492 List<TableDescriptor> tables = ADMIN.listTableDescriptors(); 493 int numTables = tables.size(); 494 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); 495 tables = ADMIN.listTableDescriptors(); 496 assertEquals(numTables + 1, tables.size()); 497 // FIRST, do htabledescriptor changes. 498 TableDescriptor htd = ADMIN.getDescriptor(tableName); 499 // Make a copy and assert copy is good. 500 TableDescriptor copy = TableDescriptorBuilder.newBuilder(htd).build(); 501 assertEquals(htd, copy); 502 String key = "anyoldkey"; 503 assertNull(htd.getValue(key)); 504 // Now amend the copy. Introduce differences. 505 long newFlushSize = htd.getMemStoreFlushSize() / 2; 506 if (newFlushSize <= 0) { 507 newFlushSize = TableDescriptorBuilder.DEFAULT_MEMSTORE_FLUSH_SIZE / 2; 508 } 509 copy = TableDescriptorBuilder.newBuilder(copy).setMemStoreFlushSize(newFlushSize) 510 .setValue(key, key).build(); 511 ADMIN.modifyTable(copy); 512 TableDescriptor modifiedHtd = ADMIN.getDescriptor(tableName); 513 assertNotEquals(htd, modifiedHtd); 514 assertEquals(copy, modifiedHtd); 515 assertEquals(newFlushSize, modifiedHtd.getMemStoreFlushSize()); 516 assertEquals(key, modifiedHtd.getValue(key)); 517 518 // Now work on column family changes. 519 int countOfFamilies = modifiedHtd.getColumnFamilyCount(); 520 assertTrue(countOfFamilies > 0); 521 ColumnFamilyDescriptor hcd = modifiedHtd.getColumnFamilies()[0]; 522 int maxversions = hcd.getMaxVersions(); 523 int newMaxVersions = maxversions + 1; 524 hcd = ColumnFamilyDescriptorBuilder.newBuilder(hcd).setMaxVersions(newMaxVersions).build(); 525 byte[] hcdName = hcd.getName(); 526 ADMIN.modifyColumnFamily(tableName, hcd); 527 modifiedHtd = ADMIN.getDescriptor(tableName); 528 ColumnFamilyDescriptor modifiedHcd = modifiedHtd.getColumnFamily(hcdName); 529 assertEquals(newMaxVersions, modifiedHcd.getMaxVersions()); 530 531 // Try adding a column 532 assertFalse(ADMIN.isTableDisabled(tableName)); 533 String xtracolName = "xtracol"; 534 ColumnFamilyDescriptor xtracol = ColumnFamilyDescriptorBuilder 535 .newBuilder(Bytes.toBytes(xtracolName)).setValue(xtracolName, xtracolName).build(); 536 ADMIN.addColumnFamily(tableName, xtracol); 537 modifiedHtd = ADMIN.getDescriptor(tableName); 538 hcd = modifiedHtd.getColumnFamily(xtracol.getName()); 539 assertNotNull(hcd); 540 assertEquals(xtracolName, Bytes.toString(hcd.getValue(Bytes.toBytes(xtracolName)))); 541 542 // Delete the just-added column. 543 ADMIN.deleteColumnFamily(tableName, xtracol.getName()); 544 modifiedHtd = ADMIN.getDescriptor(tableName); 545 hcd = modifiedHtd.getColumnFamily(xtracol.getName()); 546 assertNull(hcd); 547 548 // Delete the table 549 ADMIN.disableTable(tableName); 550 ADMIN.deleteTable(tableName); 551 ADMIN.listTableDescriptors(); 552 assertFalse(ADMIN.tableExists(tableName)); 553 } 554}