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.TableName.META_TABLE_NAME;
021import static org.hamcrest.CoreMatchers.instanceOf;
022import static org.junit.Assert.assertEquals;
023import static org.junit.Assert.assertFalse;
024import static org.junit.Assert.assertThat;
025import static org.junit.Assert.assertTrue;
026import static org.junit.Assert.fail;
027
028import java.util.List;
029import java.util.Optional;
030import java.util.concurrent.ExecutionException;
031import java.util.regex.Pattern;
032import org.apache.hadoop.hbase.AsyncMetaTableAccessor;
033import org.apache.hadoop.hbase.DoNotRetryIOException;
034import org.apache.hadoop.hbase.HBaseClassTestRule;
035import org.apache.hadoop.hbase.HRegionLocation;
036import org.apache.hadoop.hbase.TableName;
037import org.apache.hadoop.hbase.client.TableDescriptorBuilder.ModifyableTableDescriptor;
038import org.apache.hadoop.hbase.testclassification.ClientTests;
039import org.apache.hadoop.hbase.testclassification.LargeTests;
040import org.apache.hadoop.hbase.util.Bytes;
041import org.junit.ClassRule;
042import org.junit.Test;
043import org.junit.experimental.categories.Category;
044import org.junit.runner.RunWith;
045import org.junit.runners.Parameterized;
046
047/**
048 * Class to test asynchronous table admin operations.
049 * @see TestAsyncTableAdminApi2 This test and it used to be joined it was taking longer than our
050 * ten minute timeout so they were split.
051 */
052@RunWith(Parameterized.class)
053@Category({ LargeTests.class, ClientTests.class })
054public class TestAsyncTableAdminApi3 extends TestAsyncAdminBase {
055  @ClassRule
056  public static final HBaseClassTestRule CLASS_RULE =
057      HBaseClassTestRule.forClass(TestAsyncTableAdminApi3.class);
058
059  @Test
060  public void testTableExist() throws Exception {
061    boolean exist;
062    exist = admin.tableExists(tableName).get();
063    assertFalse(exist);
064    TEST_UTIL.createTable(tableName, FAMILY);
065    exist = admin.tableExists(tableName).get();
066    assertTrue(exist);
067    exist = admin.tableExists(TableName.META_TABLE_NAME).get();
068    assertTrue(exist);
069    // meta table already exists
070    exist = admin.tableExists(TableName.META_TABLE_NAME).get();
071    assertTrue(exist);
072  }
073
074  @Test
075  public void testListTables() throws Exception {
076    int numTables = admin.listTableDescriptors().get().size();
077    final TableName tableName1 = TableName.valueOf(tableName.getNameAsString() + "1");
078    final TableName tableName2 = TableName.valueOf(tableName.getNameAsString() + "2");
079    final TableName tableName3 = TableName.valueOf(tableName.getNameAsString() + "3");
080    TableName[] tables = new TableName[] { tableName1, tableName2, tableName3 };
081    for (int i = 0; i < tables.length; i++) {
082      createTableWithDefaultConf(tables[i]);
083    }
084
085    List<TableDescriptor> tableDescs = admin.listTableDescriptors().get();
086    int size = tableDescs.size();
087    assertTrue(size >= tables.length);
088    for (int i = 0; i < tables.length && i < size; i++) {
089      boolean found = false;
090      for (int j = 0; j < size; j++) {
091        if (tableDescs.get(j).getTableName().equals(tables[i])) {
092          found = true;
093          break;
094        }
095      }
096      assertTrue("Not found: " + tables[i], found);
097    }
098
099    List<TableName> tableNames = admin.listTableNames().get();
100    size = tableNames.size();
101    assertTrue(size == (numTables + tables.length));
102    for (int i = 0; i < tables.length && i < size; i++) {
103      boolean found = false;
104      for (int j = 0; j < size; j++) {
105        if (tableNames.get(j).equals(tables[i])) {
106          found = true;
107          break;
108        }
109      }
110      assertTrue("Not found: " + tables[i], found);
111    }
112
113    for (int i = 0; i < tables.length; i++) {
114      admin.disableTable(tables[i]).join();
115      admin.deleteTable(tables[i]).join();
116    }
117
118    tableDescs = admin.listTableDescriptors(true).get();
119    assertTrue("Not found system tables", tableDescs.size() > 0);
120    tableNames = admin.listTableNames(true).get();
121    assertTrue("Not found system tables", tableNames.size() > 0);
122  }
123
124  @Test
125  public void testGetTableDescriptor() throws Exception {
126    byte[][] families = { FAMILY, FAMILY_0, FAMILY_1 };
127    TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName);
128    for (byte[] family : families) {
129      builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(family));
130    }
131    TableDescriptor desc = builder.build();
132    admin.createTable(desc).join();
133    ModifyableTableDescriptor modifyableDesc = ((ModifyableTableDescriptor) desc);
134    TableDescriptor confirmedHtd = admin.getDescriptor(tableName).get();
135    assertEquals(0, modifyableDesc.compareTo((ModifyableTableDescriptor) confirmedHtd));
136  }
137
138  @Test
139  public void testDisableAndEnableTable() throws Exception {
140    createTableWithDefaultConf(tableName);
141    AsyncTable<?> table = ASYNC_CONN.getTable(tableName);
142    final byte[] row = Bytes.toBytes("row");
143    final byte[] qualifier = Bytes.toBytes("qualifier");
144    final byte[] value = Bytes.toBytes("value");
145    Put put = new Put(row);
146    put.addColumn(FAMILY, qualifier, value);
147    table.put(put).join();
148    Get get = new Get(row);
149    get.addColumn(FAMILY, qualifier);
150    table.get(get).get();
151
152    this.admin.disableTable(tableName).join();
153    assertTrue("Table must be disabled.", TEST_UTIL.getHBaseCluster().getMaster()
154        .getTableStateManager().isTableState(tableName, TableState.State.DISABLED));
155    assertEquals(TableState.State.DISABLED, TestAsyncTableAdminApi.getStateFromMeta(tableName));
156
157    // Test that table is disabled
158    get = new Get(row);
159    get.addColumn(FAMILY, qualifier);
160    boolean ok = false;
161    try {
162      table.get(get).get();
163    } catch (ExecutionException e) {
164      ok = true;
165    }
166    ok = false;
167    // verify that scan encounters correct exception
168    try {
169      table.scanAll(new Scan()).get();
170    } catch (ExecutionException e) {
171      ok = true;
172    }
173    assertTrue(ok);
174    this.admin.enableTable(tableName).join();
175    assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster().getMaster()
176        .getTableStateManager().isTableState(tableName, TableState.State.ENABLED));
177    assertEquals(TableState.State.ENABLED, TestAsyncTableAdminApi.getStateFromMeta(tableName));
178
179    // Test that table is enabled
180    try {
181      table.get(get).get();
182    } catch (Exception e) {
183      ok = false;
184    }
185    assertTrue(ok);
186    // meta table can not be disabled.
187    try {
188      admin.disableTable(TableName.META_TABLE_NAME).get();
189      fail("meta table can not be disabled");
190    } catch (ExecutionException e) {
191      Throwable cause = e.getCause();
192      assertThat(cause, instanceOf(DoNotRetryIOException.class));
193    }
194  }
195
196  @Test
197  public void testDisableAndEnableTables() throws Exception {
198    final TableName tableName1 = TableName.valueOf(tableName.getNameAsString() + "1");
199    final TableName tableName2 = TableName.valueOf(tableName.getNameAsString() + "2");
200    createTableWithDefaultConf(tableName1);
201    createTableWithDefaultConf(tableName2);
202    AsyncTable<?> table1 = ASYNC_CONN.getTable(tableName1);
203    AsyncTable<?> table2 = ASYNC_CONN.getTable(tableName1);
204
205    final byte[] row = Bytes.toBytes("row");
206    final byte[] qualifier = Bytes.toBytes("qualifier");
207    final byte[] value = Bytes.toBytes("value");
208    Put put = new Put(row);
209    put.addColumn(FAMILY, qualifier, value);
210    table1.put(put).join();
211    table2.put(put).join();
212    Get get = new Get(row);
213    get.addColumn(FAMILY, qualifier);
214    table1.get(get).get();
215    table2.get(get).get();
216
217    admin.listTableNames(Pattern.compile(tableName.getNameAsString() + ".*"), false).get()
218        .forEach(t -> admin.disableTable(t).join());
219
220    // Test that tables are disabled
221    get = new Get(row);
222    get.addColumn(FAMILY, qualifier);
223    boolean ok = false;
224    try {
225      table1.get(get).get();
226    } catch (ExecutionException e) {
227      ok = true;
228    }
229    assertTrue(ok);
230
231    ok = false;
232    try {
233      table2.get(get).get();
234    } catch (ExecutionException e) {
235      ok = true;
236    }
237    assertTrue(ok);
238    assertEquals(TableState.State.DISABLED, TestAsyncTableAdminApi.getStateFromMeta(tableName1));
239    assertEquals(TableState.State.DISABLED, TestAsyncTableAdminApi.getStateFromMeta(tableName2));
240
241    admin.listTableNames(Pattern.compile(tableName.getNameAsString() + ".*"), false).get()
242        .forEach(t -> admin.enableTable(t).join());
243
244    // Test that tables are enabled
245    try {
246      table1.get(get).get();
247    } catch (Exception e) {
248      ok = false;
249    }
250    try {
251      table2.get(get).get();
252    } catch (Exception e) {
253      ok = false;
254    }
255    assertTrue(ok);
256    assertEquals(TableState.State.ENABLED, TestAsyncTableAdminApi.getStateFromMeta(tableName1));
257    assertEquals(TableState.State.ENABLED, TestAsyncTableAdminApi.getStateFromMeta(tableName2));
258  }
259
260  @Test
261  public void testEnableTableRetainAssignment() throws Exception {
262    byte[][] splitKeys = { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, new byte[] { 3, 3, 3 },
263      new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 }, new byte[] { 6, 6, 6 },
264      new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 }, new byte[] { 9, 9, 9 } };
265    int expectedRegions = splitKeys.length + 1;
266    createTableWithDefaultConf(tableName, splitKeys);
267
268    AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME);
269    List<HRegionLocation> regions =
270      AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, Optional.of(tableName)).get();
271    assertEquals(
272      "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(),
273      expectedRegions, regions.size());
274
275    // Disable table.
276    admin.disableTable(tableName).join();
277    // Enable table, use retain assignment to assign regions.
278    admin.enableTable(tableName).join();
279
280    List<HRegionLocation> regions2 =
281      AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, Optional.of(tableName)).get();
282    // Check the assignment.
283    assertEquals(regions.size(), regions2.size());
284    assertTrue(regions2.containsAll(regions));
285  }
286
287  @Test
288  public void testIsTableEnabledAndDisabled() throws Exception {
289    createTableWithDefaultConf(tableName);
290    assertTrue(admin.isTableEnabled(tableName).get());
291    assertFalse(admin.isTableDisabled(tableName).get());
292    admin.disableTable(tableName).join();
293    assertFalse(admin.isTableEnabled(tableName).get());
294    assertTrue(admin.isTableDisabled(tableName).get());
295
296    // meta table is always enabled
297    assertTrue(admin.isTableEnabled(TableName.META_TABLE_NAME).get());
298    assertFalse(admin.isTableDisabled(TableName.META_TABLE_NAME).get());
299  }
300
301  @Test
302  public void testIsTableAvailable() throws Exception {
303    createTableWithDefaultConf(tableName);
304    TEST_UTIL.waitTableAvailable(tableName);
305    assertTrue(admin.isTableAvailable(tableName).get());
306    assertTrue(admin.isTableAvailable(TableName.META_TABLE_NAME).get());
307  }
308}