diff --git hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index 0450122..3ef9f9f 100644 --- hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -21,7 +21,6 @@ package org.apache.hadoop.hbase.client; import java.io.Closeable; import java.io.IOException; import java.io.InterruptedIOException; -import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -29,12 +28,12 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import org.apache.commons.logging.Log; @@ -59,7 +58,6 @@ import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.TableExistsException; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotDisabledException; -import org.apache.hadoop.hbase.TableNotEnabledException; import org.apache.hadoop.hbase.TableNotFoundException; import org.apache.hadoop.hbase.UnknownRegionException; import org.apache.hadoop.hbase.ZooKeeperConnectionException; @@ -100,8 +98,10 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteSnapshotReq import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteTableRequest; import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteTableResponse; import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DisableTableRequest; +import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DisableTableResponse; import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DispatchMergingRegionsRequest; import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableTableRequest; +import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableTableResponse; import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ExecProcedureRequest; import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ExecProcedureResponse; import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterStatusRequest; @@ -896,10 +896,7 @@ public class HBaseAdmin implements Admin { @Override public void enableTable(final TableName tableName) throws IOException { - enableTableAsync(tableName); - - // Wait until all regions are enabled - waitUntilTableIsEnabled(tableName); + enableTableAsyncV2(tableName); LOG.info("Enabled table " + tableName); } @@ -966,23 +963,13 @@ public class HBaseAdmin implements Admin { * @since 0.90.0 */ @Override - public void enableTableAsync(final TableName tableName) - throws IOException { - TableName.isLegalFullyQualifiedTableName(tableName.getName()); - executeCallable(new MasterCallable(getConnection()) { - @Override - public Void call(int callTimeout) throws ServiceException { - LOG.info("Started enable of " + tableName); - EnableTableRequest req = RequestConverter.buildEnableTableRequest(tableName); - master.enableTable(null,req); - return null; - } - }); + public void enableTableAsync(final TableName tableName) throws IOException { + enableTableAsyncV2(tableName); } public void enableTableAsync(final byte[] tableName) throws IOException { - enableTable(TableName.valueOf(tableName)); + enableTableAsync(TableName.valueOf(tableName)); } public void enableTableAsync(final String tableName) @@ -990,6 +977,39 @@ public class HBaseAdmin implements Admin { enableTableAsync(TableName.valueOf(tableName)); } + // TODO: change name if this method is exposed to external + private Future enableTableAsyncV2(final TableName tableName) throws IOException { + TableName.isLegalFullyQualifiedTableName(tableName.getName()); + + EnableTableResponse response = + executeCallable(new MasterCallable(getConnection()) { + @Override + public EnableTableResponse call(int callTimeout) throws ServiceException { + LOG.info("Started enable of " + tableName); + EnableTableRequest req = RequestConverter.buildEnableTableRequest(tableName); + return master.enableTable(null, req); + } + }); + return new EnableTableAyncInternal(this, tableName, response); + } + + private class EnableTableAyncInternal extends ProcedureFuture { + final TableName tableName; + + public EnableTableAyncInternal(final HBaseAdmin admin, final TableName tableName, + final EnableTableResponse response) { + super(admin, response.hasProcId() ? response.getProcId() : null); + this.tableName = tableName; + } + + @Override + protected Void postOperationResult(final Void result, final long timeoutMsec) + throws IOException, TimeoutException { + waitUntilTableIsEnabled(tableName); + return result; + } + } + /** * Enable tables matching the passed in pattern and wait on completion. * @@ -1048,16 +1068,7 @@ public class HBaseAdmin implements Admin { */ @Override public void disableTableAsync(final TableName tableName) throws IOException { - TableName.isLegalFullyQualifiedTableName(tableName.getName()); - executeCallable(new MasterCallable(getConnection()) { - @Override - public Void call(int callTimeout) throws ServiceException { - LOG.info("Started disable of " + tableName); - DisableTableRequest req = RequestConverter.buildDisableTableRequest(tableName); - master.disableTable(null,req); - return null; - } - }); + disableTableAyncV2(tableName); } public void disableTableAsync(final byte[] tableName) throws IOException { @@ -1080,33 +1091,26 @@ public class HBaseAdmin implements Admin { * TableNotEnabledException means the table isn't in enabled state. */ @Override - public void disableTable(final TableName tableName) - throws IOException { - disableTableAsync(tableName); - // Wait until table is disabled - boolean disabled = false; - for (int tries = 0; tries < (this.numRetries * this.retryLongerMultiplier); tries++) { - disabled = isTableDisabled(tableName); - if (disabled) { - break; - } - long sleep = getPauseTime(tries); - if (LOG.isDebugEnabled()) { - LOG.debug("Sleeping= " + sleep + "ms, waiting for all regions to be " + - "disabled in " + tableName); - } - try { - Thread.sleep(sleep); - } catch (InterruptedException e) { - // Do this conversion rather than let it out because do not want to - // change the method signature. - throw (InterruptedIOException)new InterruptedIOException("Interrupted").initCause(e); + public void disableTable(final TableName tableName) throws IOException { + Future future = disableTableAyncV2(tableName); + + try { + // TODO: how long should we wait? spin forever? + future.get(getTimeoutMillis(numRetries * retryLongerMultiplier), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + // Do this conversion rather than let it out because do not want to + // change the method signature. + throw (InterruptedIOException) new InterruptedIOException("Interrupted").initCause(e); + } catch (TimeoutException e) { + throw new IOException(e); // so sad.. can we break compatibility? + } catch (ExecutionException e) { + if (e.getCause() instanceof IOException) { + throw (IOException) e.getCause(); + } else { + throw new IOException(e.getCause()); } } - if (!disabled) { - throw new RegionException("Retries exhausted, it took too long to wait"+ - " for the table " + tableName + " to be disabled."); - } + LOG.info("Disabled " + tableName); } @@ -1120,6 +1124,63 @@ public class HBaseAdmin implements Admin { disableTable(TableName.valueOf(tableName)); } + // TODO: change name if this method is exposed to external + private Future disableTableAyncV2(final TableName tableName) throws IOException { + TableName.isLegalFullyQualifiedTableName(tableName.getName()); + + DisableTableResponse response = + executeCallable(new MasterCallable(getConnection()) { + @Override + public DisableTableResponse call(int callTimeout) throws ServiceException { + LOG.info("Started disable of " + tableName); + DisableTableRequest req = RequestConverter.buildDisableTableRequest(tableName); + return master.disableTable(null, req); + } + }); + return new DisableTableAyncInternal(this, tableName, response); + } + + private class DisableTableAyncInternal extends ProcedureFuture { + final TableName tableName; + + public DisableTableAyncInternal(final HBaseAdmin admin, final TableName tableName, + final DisableTableResponse response) { + super(admin, response.hasProcId() ? response.getProcId() : null); + this.tableName = tableName; + } + + @Override + protected Void postOperationResult(final Void result, final long timeoutMsec) + throws IOException, TimeoutException { + int maxTries = getAdmin().numRetries * getAdmin().retryLongerMultiplier; + // Wait until table is disabled + boolean disabled = false; + for (int tries = 0; tries < maxTries; tries++) { + disabled = isTableDisabled(tableName); + if (disabled) { + break; + } + long sleep = getPauseTime(tries); + if (LOG.isDebugEnabled()) { + LOG.debug("Sleeping= " + sleep + "ms, waiting for all regions to be " + "disabled in " + + tableName); + } + try { + Thread.sleep(sleep); + } catch (InterruptedException e) { + // Do this conversion rather than let it out because do not want to + // change the method signature. + throw (InterruptedIOException) new InterruptedIOException("Interrupted").initCause(e); + } + } + if (!disabled) { + throw new RegionException("Retries exhausted, it took too long to wait" + " for the table " + + tableName + " to be disabled."); + } + return result; + } + } + /** * Disable tables matching the passed in pattern and wait on completion. * diff --git hbase-protocol/src/main/protobuf/Master.proto hbase-protocol/src/main/protobuf/Master.proto index f1505ae..b93dc85 100644 --- hbase-protocol/src/main/protobuf/Master.proto +++ hbase-protocol/src/main/protobuf/Master.proto @@ -133,6 +133,7 @@ message EnableTableRequest { } message EnableTableResponse { + optional uint64 proc_id = 1; } message DisableTableRequest { @@ -140,6 +141,7 @@ message DisableTableRequest { } message DisableTableResponse { + optional uint64 proc_id = 1; } message ModifyTableRequest { diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 868fc0d..07eaab2 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -1644,7 +1644,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server { } @Override - public void enableTable(final TableName tableName) throws IOException { + public long enableTable(final TableName tableName) throws IOException { checkInitialized(); if (cpHost != null) { cpHost.preEnableTable(tableName); @@ -1660,12 +1660,11 @@ public class HMaster extends HRegionServer implements MasterServices, Server { cpHost.postEnableTable(tableName); } - // TODO: return procId as part of client-side change - // return procId; + return procId; } @Override - public void disableTable(final TableName tableName) throws IOException { + public long disableTable(final TableName tableName) throws IOException { checkInitialized(); if (cpHost != null) { cpHost.preDisableTable(tableName); @@ -1681,8 +1680,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server { cpHost.postDisableTable(tableName); } - // TODO: return procId as part of client-side change - // return procId; + return procId; } /** diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java index d823b35..af249e3 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java @@ -21,7 +21,6 @@ package org.apache.hadoop.hbase.master; import java.io.IOException; import java.util.List; -import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; @@ -31,9 +30,10 @@ import org.apache.hadoop.hbase.TableDescriptors; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.executor.ExecutorService; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; -import org.apache.hadoop.hbase.executor.ExecutorService; import org.apache.hadoop.hbase.quotas.MasterQuotaManager; import com.google.protobuf.Service; @@ -135,16 +135,18 @@ public interface MasterServices extends Server { /** * Enable an existing table * @param tableName The table name + * @returns procedure id * @throws IOException */ - void enableTable(final TableName tableName) throws IOException; + long enableTable(final TableName tableName) throws IOException; /** * Disable an existing table * @param tableName The table name + * @returns procedure id * @throws IOException */ - void disableTable(final TableName tableName) throws IOException; + long disableTable(final TableName tableName) throws IOException; /** diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java index 5b2e50d..3362b50 100644 --- hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java +++ hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java @@ -56,7 +56,6 @@ import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.ClusterConnection; import org.apache.hadoop.hbase.client.HConnectionTestingUtility; import org.apache.hadoop.hbase.client.Result; -import org.apache.hadoop.hbase.client.TableState; import org.apache.hadoop.hbase.coordination.BaseCoordinatedStateManager; import org.apache.hadoop.hbase.coordination.SplitLogManagerCoordination; import org.apache.hadoop.hbase.coordination.SplitLogManagerCoordination.SplitLogManagerDetails; @@ -441,10 +440,14 @@ public class TestCatalogJanitor { throws IOException { } @Override - public void enableTable(TableName tableName) throws IOException { } + public long enableTable(TableName tableName) throws IOException { + return -1; + } @Override - public void disableTable(TableName tableName) throws IOException { } + public long disableTable(TableName tableName) throws IOException { + return -1; + } @Override public void addColumn(TableName tableName, HColumnDescriptor column)