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