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}