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