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