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