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