hbase-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From zg...@apache.org
Subject hbase git commit: HBASE-17511 Implement enable/disable table methods
Date Sun, 05 Feb 2017 06:22:58 GMT
Repository: hbase
Updated Branches:
  refs/heads/master ffa0cea2a -> 26a94844f


HBASE-17511 Implement enable/disable table methods


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/26a94844
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/26a94844
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/26a94844

Branch: refs/heads/master
Commit: 26a94844f533b95db1f0a58d6a7cc3dc4a7a7098
Parents: ffa0cea
Author: Guanghao Zhang <zghao@apache.org>
Authored: Sun Feb 5 14:18:40 2017 +0800
Committer: Guanghao Zhang <zghao@apache.org>
Committed: Sun Feb 5 14:18:40 2017 +0800

----------------------------------------------------------------------
 .../hadoop/hbase/AsyncMetaTableAccessor.java    |  28 ++-
 .../apache/hadoop/hbase/client/AsyncAdmin.java  |  52 ++++++
 .../hadoop/hbase/client/AsyncHBaseAdmin.java    | 173 +++++++++++++------
 .../hadoop/hbase/client/TestAsyncAdmin.java     | 165 +++++++++++++++++-
 4 files changed, 347 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/26a94844/hbase-client/src/main/java/org/apache/hadoop/hbase/AsyncMetaTableAccessor.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/AsyncMetaTableAccessor.java
b/hbase-client/src/main/java/org/apache/hadoop/hbase/AsyncMetaTableAccessor.java
index 6b0d588..f136d56 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/AsyncMetaTableAccessor.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/AsyncMetaTableAccessor.java
@@ -27,7 +27,6 @@ import java.util.concurrent.CompletableFuture;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
-import org.apache.hadoop.hbase.client.AsyncConnection;
 import org.apache.hadoop.hbase.client.Get;
 import org.apache.hadoop.hbase.client.RawAsyncTable;
 import org.apache.hadoop.hbase.client.Result;
@@ -44,29 +43,20 @@ public class AsyncMetaTableAccessor {
 
   private static final Log LOG = LogFactory.getLog(AsyncMetaTableAccessor.class);
 
-  private static CompletableFuture<RawAsyncTable> getMetaTable(AsyncConnection conn)
{
-    return CompletableFuture.completedFuture(conn.getRawTable(META_TABLE_NAME));
-  }
-
-  public static CompletableFuture<Boolean> tableExists(AsyncConnection conn, TableName
tableName) {
+  public static CompletableFuture<Boolean> tableExists(RawAsyncTable metaTable, TableName
tableName) {
     if (tableName.equals(META_TABLE_NAME)) {
       return CompletableFuture.completedFuture(true);
     }
-    return getTableState(conn, tableName).thenApply(Optional::isPresent);
+    return getTableState(metaTable, tableName).thenApply(Optional::isPresent);
   }
 
-  public static CompletableFuture<Optional<TableState>> getTableState(AsyncConnection
conn,
+  public static CompletableFuture<Optional<TableState>> getTableState(RawAsyncTable
metaTable,
       TableName tableName) {
     CompletableFuture<Optional<TableState>> future = new CompletableFuture<>();
-    getMetaTable(conn).thenAccept((metaTable) -> {
-      Get get = new Get(tableName.getName()).addColumn(getTableFamily(), getStateColumn());
-      long time = EnvironmentEdgeManager.currentTime();
-      try {
-        get.setTimeRange(0, time);
-      } catch (IOException ioe) {
-        future.completeExceptionally(ioe);
-        return;
-      }
+    Get get = new Get(tableName.getName()).addColumn(getTableFamily(), getStateColumn());
+    long time = EnvironmentEdgeManager.currentTime();
+    try {
+      get.setTimeRange(0, time);
       metaTable.get(get).whenComplete((result, error) -> {
         if (error != null) {
           future.completeExceptionally(error);
@@ -78,7 +68,9 @@ public class AsyncMetaTableAccessor {
           future.completeExceptionally(e);
         }
       });
-    });
+    } catch (IOException ioe) {
+      future.completeExceptionally(ioe);
+    }
     return future;
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/26a94844/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
index 56036bf..29b98de 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
@@ -165,6 +165,58 @@ public interface AsyncAdmin {
   CompletableFuture<Void> truncateTable(final TableName tableName, final boolean preserveSplits);
 
   /**
+   * Enable a table. The table has to be in disabled state for it to be enabled.
+   * @param tableName name of the table
+   */
+  CompletableFuture<Void> enableTable(final TableName tableName);
+
+  /**
+   * Enable tables matching the passed in pattern. Warning: Use this method carefully, there
is no
+   * prompting and the effect is immediate. Consider using {@link #listTables(Pattern, boolean)}
and
+   * {@link #enableTable(TableName)}
+   * @param regex The regular expression to match table names against
+   * @return Table descriptors for tables that couldn't be enabled. The return value will
be wrapped
+   *         by a {@link CompletableFuture}.
+   */
+  CompletableFuture<HTableDescriptor[]> enableTables(String regex);
+
+  /**
+   * Enable tables matching the passed in pattern. Warning: Use this method carefully, there
is no
+   * prompting and the effect is immediate. Consider using {@link #listTables(Pattern, boolean)}
and
+   * {@link #enableTable(TableName)}
+   * @param pattern The pattern to match table names against
+   * @return Table descriptors for tables that couldn't be enabled. The return value will
be wrapped
+   *         by a {@link CompletableFuture}.
+   */
+  CompletableFuture<HTableDescriptor[]> enableTables(Pattern pattern);
+
+  /**
+   * Disable a table. The table has to be in enabled state for it to be disabled.
+   * @param tableName
+   */
+  CompletableFuture<Void> disableTable(final TableName tableName);
+
+  /**
+   * Disable tables matching the passed in pattern. Warning: Use this method carefully, there
is no
+   * prompting and the effect is immediate. Consider using {@link #listTables(Pattern, boolean)}
and
+   * {@link #disableTable(TableName)}
+   * @param regex The regular expression to match table names against
+   * @return Table descriptors for tables that couldn't be disabled. The return value will
be wrapped by a
+   *         {@link CompletableFuture}.
+   */
+  CompletableFuture<HTableDescriptor[]> disableTables(String regex);
+
+  /**
+   * Disable tables matching the passed in pattern. Warning: Use this method carefully, there
is no
+   * prompting and the effect is immediate. Consider using {@link #listTables(Pattern, boolean)}
and
+   * {@link #disableTable(TableName)}
+   * @param pattern The pattern to match table names against
+   * @return Table descriptors for tables that couldn't be disabled. The return value will
be wrapped by a
+   *         {@link CompletableFuture}.
+   */
+  CompletableFuture<HTableDescriptor[]> disableTables(Pattern pattern);
+
+  /**
    * Turn the load balancer on or off.
    * @param on
    * @return Previous balancer value wrapped by a {@link CompletableFuture}.

http://git-wip-us.apache.org/repos/asf/hbase/blob/26a94844/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
index 5112b90..fecdb4f 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
@@ -17,6 +17,8 @@
  */
 package org.apache.hadoop.hbase.client;
 
+import static org.apache.hadoop.hbase.TableName.META_TABLE_NAME;
+
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -43,6 +45,10 @@ import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.TableSchema;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DisableTableRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DisableTableResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableTableRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableTableResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetProcedureResultRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetProcedureResultResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
@@ -74,6 +80,8 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
 
   private final AsyncConnectionImpl connection;
 
+  private final RawAsyncTable metaTable;
+
   private final long rpcTimeoutNs;
 
   private final long operationTimeoutNs;
@@ -88,6 +96,7 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
 
   AsyncHBaseAdmin(AsyncConnectionImpl connection) {
     this.connection = connection;
+    this.metaTable = connection.getRawTable(META_TABLE_NAME);
     this.rpcTimeoutNs = connection.connConf.getRpcTimeoutNs();
     this.operationTimeoutNs = connection.connConf.getOperationTimeoutNs();
     this.pauseNs = connection.connConf.getPauseNs();
@@ -137,6 +146,46 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
     return future;
   }
 
+  private <PREQ, PRESP> CompletableFuture<Void> procedureCall(PREQ preq,
+      RpcCall<PRESP, PREQ> rpcCall, Converter<Long, PRESP> respConverter,
+      TableProcedureBiConsumer consumer) {
+    CompletableFuture<Long> procFuture = this
+        .<Long> newCaller()
+        .action(
+          (controller, stub) -> this.<PREQ, PRESP, Long> call(controller, stub,
preq, rpcCall,
+            respConverter)).call();
+    return waitProcedureResult(procFuture).whenComplete(consumer);
+  }
+
+  @FunctionalInterface
+  private interface TableOperator {
+    CompletableFuture<Void> operate(TableName table);
+  }
+
+  private CompletableFuture<HTableDescriptor[]> batchTableOperations(Pattern pattern,
+      TableOperator operator, String operationType) {
+    CompletableFuture<HTableDescriptor[]> future = new CompletableFuture<>();
+    List<HTableDescriptor> failed = new LinkedList<>();
+    listTables(pattern, false).whenComplete(
+      (tables, error) -> {
+        if (error != null) {
+          future.completeExceptionally(error);
+          return;
+        }
+        CompletableFuture[] futures = Arrays.stream(tables)
+            .map((table) -> operator.operate(table.getTableName()).whenComplete((v, ex)
-> {
+              if (ex != null) {
+                LOG.info("Failed to " + operationType + " table " + table.getTableName(),
ex);
+                failed.add(table);
+              }
+            })).toArray(size -> new CompletableFuture[size]);
+        CompletableFuture.allOf(futures).thenAccept((v) -> {
+          future.complete(failed.toArray(new HTableDescriptor[failed.size()]));
+        });
+      });
+    return future;
+  }
+
   @Override
   public AsyncConnectionImpl getConnection() {
     return this.connection;
@@ -144,12 +193,12 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
 
   @Override
   public CompletableFuture<Boolean> tableExists(TableName tableName) {
-    return AsyncMetaTableAccessor.tableExists(connection, tableName);
+    return AsyncMetaTableAccessor.tableExists(metaTable, tableName);
   }
 
   @Override
   public CompletableFuture<HTableDescriptor[]> listTables() {
-    return listTables((Pattern)null, false);
+    return listTables((Pattern) null, false);
   }
 
   @Override
@@ -171,7 +220,7 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
 
   @Override
   public CompletableFuture<TableName[]> listTableNames() {
-    return listTableNames((Pattern)null, false);
+    return listTableNames((Pattern) null, false);
   }
 
   @Override
@@ -252,29 +301,17 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
       }
     }
 
-    CompletableFuture<Long> procFuture = this
-        .<Long> newCaller()
-        .action(
-          (controller, stub) -> this.<CreateTableRequest, CreateTableResponse, Long>
call(
-            controller,
-            stub,
-            RequestConverter.buildCreateTableRequest(desc, splitKeys, ng.getNonceGroup(),
-              ng.newNonce()), (s, c, req, done) -> s.createTable(c, req, done),
-            (resp) -> resp.getProcId())).call();
-    return waitProcedureResult(procFuture).whenComplete(
+    return this.<CreateTableRequest, CreateTableResponse> procedureCall(
+      RequestConverter.buildCreateTableRequest(desc, splitKeys, ng.getNonceGroup(), ng.newNonce()),
+      (s, c, req, done) -> s.createTable(c, req, done), (resp) -> resp.getProcId(),
       new CreateTableProcedureBiConsumer(this, desc.getTableName()));
   }
 
   @Override
   public CompletableFuture<Void> deleteTable(TableName tableName) {
-    CompletableFuture<Long> procFuture = this
-        .<Long> newCaller()
-        .action(
-          (controller, stub) -> this.<DeleteTableRequest, DeleteTableResponse, Long>
call(
-            controller, stub,
-            RequestConverter.buildDeleteTableRequest(tableName, ng.getNonceGroup(), ng.newNonce()),
-            (s, c, req, done) -> s.deleteTable(c, req, done), (resp) -> resp.getProcId())).call();
-    return waitProcedureResult(procFuture).whenComplete(
+    return this.<DeleteTableRequest, DeleteTableResponse> procedureCall(RequestConverter
+        .buildDeleteTableRequest(tableName, ng.getNonceGroup(), ng.newNonce()),
+      (s, c, req, done) -> s.deleteTable(c, req, done), (resp) -> resp.getProcId(),
       new DeleteTableProcedureBiConsumer(this, tableName));
   }
 
@@ -285,41 +322,51 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
 
   @Override
   public CompletableFuture<HTableDescriptor[]> deleteTables(Pattern pattern) {
-    CompletableFuture<HTableDescriptor[]> future = new CompletableFuture<>();
-    List<HTableDescriptor> failed = new LinkedList<>();
-    listTables(pattern, false).whenComplete(
-      (tables, error) -> {
-        if (error != null) {
-          future.completeExceptionally(error);
-          return;
-        }
-        CompletableFuture[] futures = Arrays.stream(tables)
-            .map((table) -> deleteTable(table.getTableName()).whenComplete((v, ex) ->
{
-              if (ex != null) {
-                LOG.info("Failed to delete table " + table.getTableName(), ex);
-                failed.add(table);
-              }
-            })).toArray(size -> new CompletableFuture[size]);
-        CompletableFuture.allOf(futures).thenAccept((v) -> {
-          future.complete(failed.toArray(new HTableDescriptor[failed.size()]));
-        });
-      });
-    return future;
+    return batchTableOperations(pattern, (table) -> deleteTable(table), "DELETE");
   }
 
   @Override
   public CompletableFuture<Void> truncateTable(TableName tableName, boolean preserveSplits)
{
-    CompletableFuture<Long> procFuture = this
-        .<Long> newCaller()
-        .action(
-          (controller, stub) -> this.<TruncateTableRequest, TruncateTableResponse,
Long> call(
-            controller,
-            stub,
-            RequestConverter.buildTruncateTableRequest(tableName, preserveSplits,
-              ng.getNonceGroup(), ng.newNonce()),
-            (s, c, req, done) -> s.truncateTable(c, req, done), (resp) -> resp.getProcId())).call();
-    return waitProcedureResult(procFuture).whenComplete(
-      new TruncateTableProcedureBiConsumer(this, tableName));
+    return this.<TruncateTableRequest, TruncateTableResponse> procedureCall(
+      RequestConverter.buildTruncateTableRequest(tableName, preserveSplits, ng.getNonceGroup(),
+        ng.newNonce()), (s, c, req, done) -> s.truncateTable(c, req, done),
+      (resp) -> resp.getProcId(), new TruncateTableProcedureBiConsumer(this, tableName));
+  }
+
+  @Override
+  public CompletableFuture<Void> enableTable(TableName tableName) {
+    return this.<EnableTableRequest, EnableTableResponse> procedureCall(RequestConverter
+        .buildEnableTableRequest(tableName, ng.getNonceGroup(), ng.newNonce()),
+      (s, c, req, done) -> s.enableTable(c, req, done), (resp) -> resp.getProcId(),
+      new EnableTableProcedureBiConsumer(this, tableName));
+  }
+
+  @Override
+  public CompletableFuture<HTableDescriptor[]> enableTables(String regex) {
+    return enableTables(Pattern.compile(regex));
+  }
+
+  @Override
+  public CompletableFuture<HTableDescriptor[]> enableTables(Pattern pattern) {
+    return batchTableOperations(pattern, (table) -> enableTable(table), "ENABLE");
+  }
+
+  @Override
+  public CompletableFuture<Void> disableTable(TableName tableName) {
+    return this.<DisableTableRequest, DisableTableResponse> procedureCall(RequestConverter
+        .buildDisableTableRequest(tableName, ng.getNonceGroup(), ng.newNonce()),
+      (s, c, req, done) -> s.disableTable(c, req, done), (resp) -> resp.getProcId(),
+      new DisableTableProcedureBiConsumer(this, tableName));
+  }
+
+  @Override
+  public CompletableFuture<HTableDescriptor[]> disableTables(String regex) {
+    return disableTables(Pattern.compile(regex));
+  }
+
+  @Override
+  public CompletableFuture<HTableDescriptor[]> disableTables(Pattern pattern) {
+    return batchTableOperations(pattern, (table) -> disableTable(table), "DISABLE");
   }
 
   @Override
@@ -462,6 +509,28 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
     }
   }
 
+  private class EnableTableProcedureBiConsumer extends TableProcedureBiConsumer {
+
+    EnableTableProcedureBiConsumer(AsyncAdmin admin, TableName tableName) {
+      super(admin, tableName);
+    }
+
+    String getOperationType() {
+      return "ENABLE";
+    }
+  }
+
+  private class DisableTableProcedureBiConsumer extends TableProcedureBiConsumer {
+
+    DisableTableProcedureBiConsumer(AsyncAdmin admin, TableName tableName) {
+      super(admin, tableName);
+    }
+
+    String getOperationType() {
+      return "DISABLE";
+    }
+  }
+
   private CompletableFuture<Void> waitProcedureResult(CompletableFuture<Long>
procFuture) {
     CompletableFuture<Void> future = new CompletableFuture<>();
     procFuture.whenComplete((procId, error) -> {

http://git-wip-us.apache.org/repos/asf/hbase/blob/26a94844/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdmin.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdmin.java
b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdmin.java
index 0835b47..8ba5dc7 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdmin.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdmin.java
@@ -18,6 +18,7 @@
 package org.apache.hadoop.hbase.client;
 
 import static org.apache.hadoop.hbase.client.AsyncProcess.START_LOG_ERRORS_AFTER_COUNT_KEY;
+import static org.apache.hadoop.hbase.TableName.META_TABLE_NAME;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
@@ -46,6 +47,9 @@ import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.TableNotDisabledException;
+import org.apache.hadoop.hbase.TableNotEnabledException;
+import org.apache.hadoop.hbase.constraint.ConstraintException;
 import org.apache.hadoop.hbase.testclassification.ClientTests;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.util.Bytes;
@@ -181,7 +185,8 @@ public class TestAsyncAdmin {
   }
 
   private TableState.State getStateFromMeta(TableName table) throws Exception {
-    Optional<TableState> state = AsyncMetaTableAccessor.getTableState(ASYNC_CONN, table).get();
+    Optional<TableState> state = AsyncMetaTableAccessor.getTableState(
+      ASYNC_CONN.getRawTable(META_TABLE_NAME), table).get();
     assertTrue(state.isPresent());
     return state.get().getState();
   }
@@ -520,6 +525,164 @@ public class TestAsyncAdmin {
     }
   }
 
+  @Test(timeout = 300000)
+  public void testDisableAndEnableTable() throws Exception {
+    final byte[] row = Bytes.toBytes("row");
+    final byte[] qualifier = Bytes.toBytes("qualifier");
+    final byte[] value = Bytes.toBytes("value");
+    final TableName table = TableName.valueOf("testDisableAndEnableTable");
+    Table ht = TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY);
+    Put put = new Put(row);
+    put.addColumn(HConstants.CATALOG_FAMILY, qualifier, value);
+    ht.put(put);
+    Get get = new Get(row);
+    get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
+    ht.get(get);
+
+    this.admin.disableTable(ht.getName()).join();
+    assertTrue("Table must be disabled.", TEST_UTIL.getHBaseCluster().getMaster()
+        .getTableStateManager().isTableState(ht.getName(), TableState.State.DISABLED));
+    assertEquals(TableState.State.DISABLED, getStateFromMeta(table));
+
+    // Test that table is disabled
+    get = new Get(row);
+    get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
+    boolean ok = false;
+    try {
+      ht.get(get);
+    } catch (TableNotEnabledException e) {
+      ok = true;
+    }
+    ok = false;
+    // verify that scan encounters correct exception
+    Scan scan = new Scan();
+    try {
+      ResultScanner scanner = ht.getScanner(scan);
+      Result res = null;
+      do {
+        res = scanner.next();
+      } while (res != null);
+    } catch (TableNotEnabledException e) {
+      ok = true;
+    }
+    assertTrue(ok);
+    this.admin.enableTable(table).join();
+    assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster().getMaster()
+        .getTableStateManager().isTableState(ht.getName(), TableState.State.ENABLED));
+    assertEquals(TableState.State.ENABLED, getStateFromMeta(table));
+
+    // Test that table is enabled
+    try {
+      ht.get(get);
+    } catch (RetriesExhaustedException e) {
+      ok = false;
+    }
+    assertTrue(ok);
+    ht.close();
+  }
+
+  @Test(timeout = 300000)
+  public void testDisableAndEnableTables() throws Exception {
+    final byte[] row = Bytes.toBytes("row");
+    final byte[] qualifier = Bytes.toBytes("qualifier");
+    final byte[] value = Bytes.toBytes("value");
+    final TableName table1 = TableName.valueOf("testDisableAndEnableTable1");
+    final TableName table2 = TableName.valueOf("testDisableAndEnableTable2");
+    Table ht1 = TEST_UTIL.createTable(table1, HConstants.CATALOG_FAMILY);
+    Table ht2 = TEST_UTIL.createTable(table2, HConstants.CATALOG_FAMILY);
+    Put put = new Put(row);
+    put.addColumn(HConstants.CATALOG_FAMILY, qualifier, value);
+    ht1.put(put);
+    ht2.put(put);
+    Get get = new Get(row);
+    get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
+    ht1.get(get);
+    ht2.get(get);
+
+    this.admin.disableTables("testDisableAndEnableTable.*").join();
+
+    // Test that tables are disabled
+    get = new Get(row);
+    get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
+    boolean ok = false;
+    try {
+      ht1.get(get);
+      ht2.get(get);
+    } catch (org.apache.hadoop.hbase.DoNotRetryIOException e) {
+      ok = true;
+    }
+
+    assertEquals(TableState.State.DISABLED, getStateFromMeta(table1));
+    assertEquals(TableState.State.DISABLED, getStateFromMeta(table2));
+
+    assertTrue(ok);
+    this.admin.enableTables("testDisableAndEnableTable.*").join();
+
+    // Test that tables are enabled
+    try {
+      ht1.get(get);
+    } catch (IOException e) {
+      ok = false;
+    }
+    try {
+      ht2.get(get);
+    } catch (IOException e) {
+      ok = false;
+    }
+    assertTrue(ok);
+
+    ht1.close();
+    ht2.close();
+
+    assertEquals(TableState.State.ENABLED, getStateFromMeta(table1));
+    assertEquals(TableState.State.ENABLED, getStateFromMeta(table2));
+  }
+
+  @Test(timeout = 300000)
+  public void testEnableTableRetainAssignment() throws Exception {
+    final TableName tableName = TableName.valueOf("testEnableTableAssignment");
+    byte[][] splitKeys = { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, new byte[] { 3,
3, 3 },
+        new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 }, new byte[] { 6, 6, 6 },
+        new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 }, new byte[] { 9, 9, 9 } };
+    int expectedRegions = splitKeys.length + 1;
+    HTableDescriptor desc = new HTableDescriptor(tableName);
+    desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
+    admin.createTable(desc, splitKeys).join();
+
+    try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
+      List<HRegionLocation> regions = l.getAllRegionLocations();
+
+      assertEquals(
+        "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(),
+        expectedRegions, regions.size());
+      // Disable table.
+      admin.disableTable(tableName).join();
+      // Enable table, use retain assignment to assign regions.
+      admin.enableTable(tableName).join();
+      List<HRegionLocation> regions2 = l.getAllRegionLocations();
+
+      // Check the assignment.
+      assertEquals(regions.size(), regions2.size());
+      assertTrue(regions2.containsAll(regions));
+    }
+  }
+
+  @Test(timeout = 300000)
+  public void testDisableCatalogTable() throws Exception {
+    try {
+      this.admin.disableTable(TableName.META_TABLE_NAME).join();
+      fail("Expected to throw ConstraintException");
+    } catch (Exception e) {
+    }
+    // Before the fix for HBASE-6146, the below table creation was failing as the hbase:meta
table
+    // actually getting disabled by the disableTable() call.
+    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("testDisableCatalogTable"
+        .getBytes()));
+    HColumnDescriptor hcd = new HColumnDescriptor("cf1".getBytes());
+    htd.addFamily(hcd);
+    admin.createTable(htd).join();
+  }
+
   @Test(timeout = 30000)
   public void testBalancer() throws Exception {
     boolean initialState = admin.isBalancerEnabled().get();


Mime
View raw message