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