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