diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterAdminProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterAdminProtos.java index 71be12a..245a941 100644 --- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterAdminProtos.java +++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterAdminProtos.java @@ -7361,6 +7361,10 @@ public final class MasterAdminProtos { // required bytes tableName = 1; boolean hasTableName(); com.google.protobuf.ByteString getTableName(); + + // required bool force = 2; + boolean hasForce(); + boolean getForce(); } public static final class EnableTableRequest extends com.google.protobuf.GeneratedMessage @@ -7401,8 +7405,19 @@ public final class MasterAdminProtos { return tableName_; } + // required bool force = 2; + public static final int FORCE_FIELD_NUMBER = 2; + private boolean force_; + public boolean hasForce() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public boolean getForce() { + return force_; + } + private void initFields() { tableName_ = com.google.protobuf.ByteString.EMPTY; + force_ = false; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -7413,6 +7428,10 @@ public final class MasterAdminProtos { memoizedIsInitialized = 0; return false; } + if (!hasForce()) { + memoizedIsInitialized = 0; + return false; + } memoizedIsInitialized = 1; return true; } @@ -7423,6 +7442,9 @@ public final class MasterAdminProtos { if (((bitField0_ & 0x00000001) == 0x00000001)) { output.writeBytes(1, tableName_); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBool(2, force_); + } getUnknownFields().writeTo(output); } @@ -7436,6 +7458,10 @@ public final class MasterAdminProtos { size += com.google.protobuf.CodedOutputStream .computeBytesSize(1, tableName_); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(2, force_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -7464,6 +7490,11 @@ public final class MasterAdminProtos { result = result && getTableName() .equals(other.getTableName()); } + result = result && (hasForce() == other.hasForce()); + if (hasForce()) { + result = result && (getForce() + == other.getForce()); + } result = result && getUnknownFields().equals(other.getUnknownFields()); return result; @@ -7477,6 +7508,10 @@ public final class MasterAdminProtos { hash = (37 * hash) + TABLENAME_FIELD_NUMBER; hash = (53 * hash) + getTableName().hashCode(); } + if (hasForce()) { + hash = (37 * hash) + FORCE_FIELD_NUMBER; + hash = (53 * hash) + hashBoolean(getForce()); + } hash = (29 * hash) + getUnknownFields().hashCode(); return hash; } @@ -7595,6 +7630,8 @@ public final class MasterAdminProtos { super.clear(); tableName_ = com.google.protobuf.ByteString.EMPTY; bitField0_ = (bitField0_ & ~0x00000001); + force_ = false; + bitField0_ = (bitField0_ & ~0x00000002); return this; } @@ -7637,6 +7674,10 @@ public final class MasterAdminProtos { to_bitField0_ |= 0x00000001; } result.tableName_ = tableName_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.force_ = force_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -7656,6 +7697,9 @@ public final class MasterAdminProtos { if (other.hasTableName()) { setTableName(other.getTableName()); } + if (other.hasForce()) { + setForce(other.getForce()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -7665,6 +7709,10 @@ public final class MasterAdminProtos { return false; } + if (!hasForce()) { + + return false; + } return true; } @@ -7696,6 +7744,11 @@ public final class MasterAdminProtos { tableName_ = input.readBytes(); break; } + case 16: { + bitField0_ |= 0x00000002; + force_ = input.readBool(); + break; + } } } } @@ -7726,6 +7779,27 @@ public final class MasterAdminProtos { return this; } + // required bool force = 2; + private boolean force_ ; + public boolean hasForce() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public boolean getForce() { + return force_; + } + public Builder setForce(boolean value) { + bitField0_ |= 0x00000002; + force_ = value; + onChanged(); + return this; + } + public Builder clearForce() { + bitField0_ = (bitField0_ & ~0x00000002); + force_ = false; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:EnableTableRequest) } @@ -8043,6 +8117,10 @@ public final class MasterAdminProtos { // required bytes tableName = 1; boolean hasTableName(); com.google.protobuf.ByteString getTableName(); + + // required bool force = 2; + boolean hasForce(); + boolean getForce(); } public static final class DisableTableRequest extends com.google.protobuf.GeneratedMessage @@ -8083,8 +8161,19 @@ public final class MasterAdminProtos { return tableName_; } + // required bool force = 2; + public static final int FORCE_FIELD_NUMBER = 2; + private boolean force_; + public boolean hasForce() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public boolean getForce() { + return force_; + } + private void initFields() { tableName_ = com.google.protobuf.ByteString.EMPTY; + force_ = false; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -8095,6 +8184,10 @@ public final class MasterAdminProtos { memoizedIsInitialized = 0; return false; } + if (!hasForce()) { + memoizedIsInitialized = 0; + return false; + } memoizedIsInitialized = 1; return true; } @@ -8105,6 +8198,9 @@ public final class MasterAdminProtos { if (((bitField0_ & 0x00000001) == 0x00000001)) { output.writeBytes(1, tableName_); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBool(2, force_); + } getUnknownFields().writeTo(output); } @@ -8118,6 +8214,10 @@ public final class MasterAdminProtos { size += com.google.protobuf.CodedOutputStream .computeBytesSize(1, tableName_); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(2, force_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -8146,6 +8246,11 @@ public final class MasterAdminProtos { result = result && getTableName() .equals(other.getTableName()); } + result = result && (hasForce() == other.hasForce()); + if (hasForce()) { + result = result && (getForce() + == other.getForce()); + } result = result && getUnknownFields().equals(other.getUnknownFields()); return result; @@ -8159,6 +8264,10 @@ public final class MasterAdminProtos { hash = (37 * hash) + TABLENAME_FIELD_NUMBER; hash = (53 * hash) + getTableName().hashCode(); } + if (hasForce()) { + hash = (37 * hash) + FORCE_FIELD_NUMBER; + hash = (53 * hash) + hashBoolean(getForce()); + } hash = (29 * hash) + getUnknownFields().hashCode(); return hash; } @@ -8277,6 +8386,8 @@ public final class MasterAdminProtos { super.clear(); tableName_ = com.google.protobuf.ByteString.EMPTY; bitField0_ = (bitField0_ & ~0x00000001); + force_ = false; + bitField0_ = (bitField0_ & ~0x00000002); return this; } @@ -8319,6 +8430,10 @@ public final class MasterAdminProtos { to_bitField0_ |= 0x00000001; } result.tableName_ = tableName_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.force_ = force_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -8338,6 +8453,9 @@ public final class MasterAdminProtos { if (other.hasTableName()) { setTableName(other.getTableName()); } + if (other.hasForce()) { + setForce(other.getForce()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -8347,6 +8465,10 @@ public final class MasterAdminProtos { return false; } + if (!hasForce()) { + + return false; + } return true; } @@ -8378,6 +8500,11 @@ public final class MasterAdminProtos { tableName_ = input.readBytes(); break; } + case 16: { + bitField0_ |= 0x00000002; + force_ = input.readBool(); + break; + } } } } @@ -8408,6 +8535,27 @@ public final class MasterAdminProtos { return this; } + // required bool force = 2; + private boolean force_ ; + public boolean hasForce() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public boolean getForce() { + return force_; + } + public Builder setForce(boolean value) { + bitField0_ |= 0x00000002; + force_ = value; + onChanged(); + return this; + } + public Builder clearForce() { + bitField0_ = (bitField0_ & ~0x00000002); + force_ = false; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:DisableTableRequest) } @@ -16041,59 +16189,60 @@ public final class MasterAdminProtos { "ableSchema\030\001 \002(\0132\014.TableSchema\022\021\n\tsplitK", "eys\030\002 \003(\014\"\025\n\023CreateTableResponse\"\'\n\022Dele" + "teTableRequest\022\021\n\ttableName\030\001 \002(\014\"\025\n\023Del" + - "eteTableResponse\"\'\n\022EnableTableRequest\022\021" + - "\n\ttableName\030\001 \002(\014\"\025\n\023EnableTableResponse" + - "\"(\n\023DisableTableRequest\022\021\n\ttableName\030\001 \002" + - "(\014\"\026\n\024DisableTableResponse\"J\n\022ModifyTabl" + - "eRequest\022\021\n\ttableName\030\001 \002(\014\022!\n\013tableSche" + - "ma\030\002 \002(\0132\014.TableSchema\"\025\n\023ModifyTableRes" + - "ponse\"\021\n\017ShutdownRequest\"\022\n\020ShutdownResp" + - "onse\"\023\n\021StopMasterRequest\"\024\n\022StopMasterR", - "esponse\"\020\n\016BalanceRequest\"&\n\017BalanceResp" + - "onse\022\023\n\013balancerRan\030\001 \002(\010\"<\n\031SetBalancer" + - "RunningRequest\022\n\n\002on\030\001 \002(\010\022\023\n\013synchronou" + - "s\030\002 \001(\010\"6\n\032SetBalancerRunningResponse\022\030\n" + - "\020prevBalanceValue\030\001 \001(\010\"\024\n\022CatalogScanRe" + - "quest\")\n\023CatalogScanResponse\022\022\n\nscanResu" + - "lt\030\001 \001(\005\"-\n\033EnableCatalogJanitorRequest\022" + - "\016\n\006enable\030\001 \002(\010\"1\n\034EnableCatalogJanitorR" + - "esponse\022\021\n\tprevValue\030\001 \001(\010\" \n\036IsCatalogJ" + - "anitorEnabledRequest\"0\n\037IsCatalogJanitor", - "EnabledResponse\022\r\n\005value\030\001 \002(\0102\201\n\n\022Maste" + - "rAdminService\0222\n\taddColumn\022\021.AddColumnRe" + - "quest\032\022.AddColumnResponse\022;\n\014deleteColum" + - "n\022\024.DeleteColumnRequest\032\025.DeleteColumnRe" + - "sponse\022;\n\014modifyColumn\022\024.ModifyColumnReq" + - "uest\032\025.ModifyColumnResponse\0225\n\nmoveRegio" + - "n\022\022.MoveRegionRequest\032\023.MoveRegionRespon" + - "se\022;\n\014assignRegion\022\024.AssignRegionRequest" + - "\032\025.AssignRegionResponse\022A\n\016unassignRegio" + - "n\022\026.UnassignRegionRequest\032\027.UnassignRegi", - "onResponse\022>\n\rofflineRegion\022\025.OfflineReg" + - "ionRequest\032\026.OfflineRegionResponse\0228\n\013de" + - "leteTable\022\023.DeleteTableRequest\032\024.DeleteT" + - "ableResponse\0228\n\013enableTable\022\023.EnableTabl" + - "eRequest\032\024.EnableTableResponse\022;\n\014disabl" + - "eTable\022\024.DisableTableRequest\032\025.DisableTa" + - "bleResponse\0228\n\013modifyTable\022\023.ModifyTable" + - "Request\032\024.ModifyTableResponse\0228\n\013createT" + - "able\022\023.CreateTableRequest\032\024.CreateTableR" + - "esponse\022/\n\010shutdown\022\020.ShutdownRequest\032\021.", - "ShutdownResponse\0225\n\nstopMaster\022\022.StopMas" + - "terRequest\032\023.StopMasterResponse\022,\n\007balan" + - "ce\022\017.BalanceRequest\032\020.BalanceResponse\022M\n" + - "\022setBalancerRunning\022\032.SetBalancerRunning" + - "Request\032\033.SetBalancerRunningResponse\022;\n\016" + - "runCatalogScan\022\023.CatalogScanRequest\032\024.Ca" + - "talogScanResponse\022S\n\024enableCatalogJanito" + - "r\022\034.EnableCatalogJanitorRequest\032\035.Enable" + - "CatalogJanitorResponse\022\\\n\027isCatalogJanit" + - "orEnabled\022\037.IsCatalogJanitorEnabledReque", - "st\032 .IsCatalogJanitorEnabledResponse\022L\n\021" + - "execMasterService\022\032.CoprocessorServiceRe" + - "quest\032\033.CoprocessorServiceResponseBG\n*or" + - "g.apache.hadoop.hbase.protobuf.generated" + - "B\021MasterAdminProtosH\001\210\001\001\240\001\001" + "eteTableResponse\"6\n\022EnableTableRequest\022\021" + + "\n\ttableName\030\001 \002(\014\022\r\n\005force\030\002 \002(\010\"\025\n\023Enab" + + "leTableResponse\"7\n\023DisableTableRequest\022\021" + + "\n\ttableName\030\001 \002(\014\022\r\n\005force\030\002 \002(\010\"\026\n\024Disa" + + "bleTableResponse\"J\n\022ModifyTableRequest\022\021" + + "\n\ttableName\030\001 \002(\014\022!\n\013tableSchema\030\002 \002(\0132\014" + + ".TableSchema\"\025\n\023ModifyTableResponse\"\021\n\017S" + + "hutdownRequest\"\022\n\020ShutdownResponse\"\023\n\021St", + "opMasterRequest\"\024\n\022StopMasterResponse\"\020\n" + + "\016BalanceRequest\"&\n\017BalanceResponse\022\023\n\013ba" + + "lancerRan\030\001 \002(\010\"<\n\031SetBalancerRunningReq" + + "uest\022\n\n\002on\030\001 \002(\010\022\023\n\013synchronous\030\002 \001(\010\"6\n" + + "\032SetBalancerRunningResponse\022\030\n\020prevBalan" + + "ceValue\030\001 \001(\010\"\024\n\022CatalogScanRequest\")\n\023C" + + "atalogScanResponse\022\022\n\nscanResult\030\001 \001(\005\"-" + + "\n\033EnableCatalogJanitorRequest\022\016\n\006enable\030" + + "\001 \002(\010\"1\n\034EnableCatalogJanitorResponse\022\021\n" + + "\tprevValue\030\001 \001(\010\" \n\036IsCatalogJanitorEnab", + "ledRequest\"0\n\037IsCatalogJanitorEnabledRes" + + "ponse\022\r\n\005value\030\001 \002(\0102\201\n\n\022MasterAdminServ" + + "ice\0222\n\taddColumn\022\021.AddColumnRequest\032\022.Ad" + + "dColumnResponse\022;\n\014deleteColumn\022\024.Delete" + + "ColumnRequest\032\025.DeleteColumnResponse\022;\n\014" + + "modifyColumn\022\024.ModifyColumnRequest\032\025.Mod" + + "ifyColumnResponse\0225\n\nmoveRegion\022\022.MoveRe" + + "gionRequest\032\023.MoveRegionResponse\022;\n\014assi" + + "gnRegion\022\024.AssignRegionRequest\032\025.AssignR" + + "egionResponse\022A\n\016unassignRegion\022\026.Unassi", + "gnRegionRequest\032\027.UnassignRegionResponse" + + "\022>\n\rofflineRegion\022\025.OfflineRegionRequest" + + "\032\026.OfflineRegionResponse\0228\n\013deleteTable\022" + + "\023.DeleteTableRequest\032\024.DeleteTableRespon" + + "se\0228\n\013enableTable\022\023.EnableTableRequest\032\024" + + ".EnableTableResponse\022;\n\014disableTable\022\024.D" + + "isableTableRequest\032\025.DisableTableRespons" + + "e\0228\n\013modifyTable\022\023.ModifyTableRequest\032\024." + + "ModifyTableResponse\0228\n\013createTable\022\023.Cre" + + "ateTableRequest\032\024.CreateTableResponse\022/\n", + "\010shutdown\022\020.ShutdownRequest\032\021.ShutdownRe" + + "sponse\0225\n\nstopMaster\022\022.StopMasterRequest" + + "\032\023.StopMasterResponse\022,\n\007balance\022\017.Balan" + + "ceRequest\032\020.BalanceResponse\022M\n\022setBalanc" + + "erRunning\022\032.SetBalancerRunningRequest\032\033." + + "SetBalancerRunningResponse\022;\n\016runCatalog" + + "Scan\022\023.CatalogScanRequest\032\024.CatalogScanR" + + "esponse\022S\n\024enableCatalogJanitor\022\034.Enable" + + "CatalogJanitorRequest\032\035.EnableCatalogJan" + + "itorResponse\022\\\n\027isCatalogJanitorEnabled\022", + "\037.IsCatalogJanitorEnabledRequest\032 .IsCat" + + "alogJanitorEnabledResponse\022L\n\021execMaster" + + "Service\022\032.CoprocessorServiceRequest\032\033.Co" + + "processorServiceResponseBG\n*org.apache.h" + + "adoop.hbase.protobuf.generatedB\021MasterAd" + + "minProtosH\001\210\001\001\240\001\001" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -16249,7 +16398,7 @@ public final class MasterAdminProtos { internal_static_EnableTableRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_EnableTableRequest_descriptor, - new java.lang.String[] { "TableName", }, + new java.lang.String[] { "TableName", "Force", }, org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableTableRequest.class, org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableTableRequest.Builder.class); internal_static_EnableTableResponse_descriptor = @@ -16265,7 +16414,7 @@ public final class MasterAdminProtos { internal_static_DisableTableRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_DisableTableRequest_descriptor, - new java.lang.String[] { "TableName", }, + new java.lang.String[] { "TableName", "Force", }, org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DisableTableRequest.class, org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DisableTableRequest.Builder.class); internal_static_DisableTableResponse_descriptor = diff --git a/hbase-protocol/src/main/protobuf/MasterAdmin.proto b/hbase-protocol/src/main/protobuf/MasterAdmin.proto index dc62bb4..8d4729a 100644 --- a/hbase-protocol/src/main/protobuf/MasterAdmin.proto +++ b/hbase-protocol/src/main/protobuf/MasterAdmin.proto @@ -104,6 +104,7 @@ message DeleteTableResponse { message EnableTableRequest { required bytes tableName = 1; + required bool force = 2; } message EnableTableResponse { @@ -111,6 +112,7 @@ message EnableTableResponse { message DisableTableRequest { required bytes tableName = 1; + required bool force = 2; } message DisableTableResponse { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/MasterAdminProtocol.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/MasterAdminProtocol.java index cba99e2..8bb4a4f 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/MasterAdminProtocol.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/MasterAdminProtocol.java @@ -214,7 +214,8 @@ public interface MasterAdminProtocol extends * Puts the table on-line (only needed if table has been previously taken offline) * @param controller Unused (set to null). * @param req EnableTableRequest that contains:
- * - tableName: table to enable + * - tableName: table to enable
+ * - force: force enablement * @throws ServiceException */ @Override @@ -226,7 +227,8 @@ public interface MasterAdminProtocol extends * * @param controller Unused (set to null). * @param req DisableTableRequest that contains:
- * - tableName: table to take offline + * - tableName: table to take offline
+ * - force: force disablement * @throws ServiceException */ @Override diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index cdb72a1..840d697 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -650,14 +650,27 @@ public class HBaseAdmin implements Abortable, Closeable { public void enableTable(final String tableName) throws IOException { - enableTable(Bytes.toBytes(tableName)); + enableTable(Bytes.toBytes(tableName), false); + } + + public void enableTable(final String tableName, final boolean force) + throws IOException { + enableTable(Bytes.toBytes(tableName), force); + } + + public void enableTable(final byte [] tableName) + throws IOException { + enableTable(tableName, false); } /** * Enable a table. May timeout. Use {@link #enableTableAsync(byte[])} * and {@link #isTableEnabled(byte[])} instead. - * The table has to be in disabled state for it to be enabled. - * @param tableName name of the table + * The table has to be in disabled state for it to be enabled, + * unless force is specified. + * @param tableName Name of the table + * @param force Force enablement state in ZK. For use in conjunction + * with hbck. * @throws IOException if a remote or network exception occurs * There could be couple types of IOException * TableNotFoundException means the table doesn't exist. @@ -666,9 +679,9 @@ public class HBaseAdmin implements Abortable, Closeable { * @see #disableTable(byte[]) * @see #enableTableAsync(byte[]) */ - public void enableTable(final byte [] tableName) + public void enableTable(final byte [] tableName, final boolean force) throws IOException { - enableTableAsync(tableName); + enableTableAsync(tableName, force); // Wait until all regions are enabled boolean enabled = false; @@ -700,7 +713,12 @@ public class HBaseAdmin implements Abortable, Closeable { public void enableTableAsync(final String tableName) throws IOException { - enableTableAsync(Bytes.toBytes(tableName)); + enableTableAsync(Bytes.toBytes(tableName), false); + } + + public void enableTableAsync(final String tableName, final boolean force) + throws IOException { + enableTableAsync(Bytes.toBytes(tableName), force); } /** @@ -709,18 +727,24 @@ public class HBaseAdmin implements Abortable, Closeable { * is large (All regions are opened as part of enabling process). Check * {@link #isTableEnabled(byte[])} to learn when table is fully online. If * table is taking too long to online, check server logs. - * @param tableName + * @param tableName Name of table + * @param force Force enablement state in ZK. For use in conjunction + * with hbck * @throws IOException * @since 0.90.0 */ - public void enableTableAsync(final byte [] tableName) + public void enableTableAsync(final byte [] tableName, final boolean force) throws IOException { HTableDescriptor.isLegalTableName(tableName); execute(new MasterAdminCallable() { @Override public Void call() throws ServiceException { - LOG.info("Started enable of " + Bytes.toString(tableName)); - EnableTableRequest req = RequestConverter.buildEnableTableRequest(tableName); + if (force) { + LOG.warn("Forcing enable of " + Bytes.toString(tableName)); + } else { + LOG.info("Started enable of " + Bytes.toString(tableName)); + } + EnableTableRequest req = RequestConverter.buildEnableTableRequest(tableName, force); masterAdmin.enableTable(null,req); return null; } @@ -740,7 +764,24 @@ public class HBaseAdmin implements Abortable, Closeable { * @see #enableTable(java.lang.String) */ public HTableDescriptor[] enableTables(String regex) throws IOException { - return enableTables(Pattern.compile(regex)); + return enableTables(Pattern.compile(regex), false); + } + + /** + * Enable tables matching the passed in pattern and wait on completion. + * + * Warning: Use this method carefully, there is no prompting and the effect is + * immediate. Consider using {@link #listTables(java.lang.String)} and + * {@link #enableTable(byte[])} + * + * @param regex The regular expression to match table names against + * @param force When true, force change of the table state in ZK + * @throws IOException + * @see #enableTables(java.util.regex.Pattern) + * @see #enableTable(java.lang.String) + */ + public HTableDescriptor[] enableTables(String regex, boolean force) throws IOException { + return enableTables(Pattern.compile(regex), force); } /** @@ -754,11 +795,26 @@ public class HBaseAdmin implements Abortable, Closeable { * @throws IOException */ public HTableDescriptor[] enableTables(Pattern pattern) throws IOException { + return enableTables(pattern, false); + } + + /** + * Enable tables matching the passed in pattern and wait on completion. + * + * Warning: Use this method carefully, there is no prompting and the effect is + * immediate. Consider using {@link #listTables(java.util.regex.Pattern) } and + * {@link #enableTable(byte[])} + * + * @param pattern The pattern to match table names against + * @param force When true, force change of the table state in ZK + * @throws IOException + */ + public HTableDescriptor[] enableTables(Pattern pattern, boolean force) throws IOException { List failed = new LinkedList(); for (HTableDescriptor table : listTables(pattern)) { if (isTableDisabled(table.getName())) { try { - enableTable(table.getName()); + enableTable(table.getName(), force); } catch (IOException ex) { LOG.info("Failed to enable table " + table.getNameAsString(), ex); failed.add(table); @@ -769,7 +825,16 @@ public class HBaseAdmin implements Abortable, Closeable { } public void disableTableAsync(final String tableName) throws IOException { - disableTableAsync(Bytes.toBytes(tableName)); + disableTableAsync(Bytes.toBytes(tableName), false); + } + + public void disableTableAsync(final String tableName, final boolean force) + throws IOException { + disableTableAsync(Bytes.toBytes(tableName), force); + } + + public void disableTableAsync(final byte [] tableName) throws IOException { + disableTableAsync(tableName, false); } /** @@ -780,18 +845,25 @@ public class HBaseAdmin implements Abortable, Closeable { * Call {@link #isTableDisabled(byte[])} to check for when disable completes. * If table is taking too long to online, check server logs. * @param tableName name of table + * @param force Force enablement state in ZK. For use in conjunction + * with hbck * @throws IOException if a remote or network exception occurs * @see #isTableDisabled(byte[]) * @see #isTableEnabled(byte[]) * @since 0.90.0 */ - public void disableTableAsync(final byte [] tableName) throws IOException { + public void disableTableAsync(final byte [] tableName, final boolean force) + throws IOException { HTableDescriptor.isLegalTableName(tableName); execute(new MasterAdminCallable() { @Override public Void call() throws ServiceException { - LOG.info("Started disable of " + Bytes.toString(tableName)); - DisableTableRequest req = RequestConverter.buildDisableTableRequest(tableName); + if (force) { + LOG.warn("Forcing disable of " + Bytes.toString(tableName)); + } else { + LOG.info("Started disable of " + Bytes.toString(tableName)); + } + DisableTableRequest req = RequestConverter.buildDisableTableRequest(tableName, force); masterAdmin.disableTable(null,req); return null; } @@ -800,23 +872,36 @@ public class HBaseAdmin implements Abortable, Closeable { public void disableTable(final String tableName) throws IOException { - disableTable(Bytes.toBytes(tableName)); + disableTable(Bytes.toBytes(tableName), false); + } + + public void disableTable(final String tableName, final boolean force) + throws IOException { + disableTable(Bytes.toBytes(tableName), force); + } + + public void disableTable(final byte [] tableName) + throws IOException { + disableTable(tableName, false); } /** * Disable table and wait on completion. May timeout eventually. Use * {@link #disableTableAsync(byte[])} and {@link #isTableDisabled(String)} * instead. - * The table has to be in enabled state for it to be disabled. - * @param tableName + * The table has to be in enabled state for it to be disabled, + * unless force is specified. + * @param tableName Name of the table + * @param force Force disablement state in ZK. For use in + * conjunction with hbck. * @throws IOException * There could be couple types of IOException * TableNotFoundException means the table doesn't exist. * TableNotEnabledException means the table isn't in enabled state. */ - public void disableTable(final byte [] tableName) + public void disableTable(final byte [] tableName, final boolean force) throws IOException { - disableTableAsync(tableName); + disableTableAsync(tableName, force); // Wait until table is disabled boolean disabled = false; for (int tries = 0; tries < (this.numRetries * this.retryLongerMultiplier); tries++) { @@ -859,7 +944,26 @@ public class HBaseAdmin implements Abortable, Closeable { * @see #disableTable(java.lang.String) */ public HTableDescriptor[] disableTables(String regex) throws IOException { - return disableTables(Pattern.compile(regex)); + return disableTables(Pattern.compile(regex), false); + } + + /** + * Disable tables matching the passed in pattern and wait on completion. + * + * Warning: Use this method carefully, there is no prompting and the effect is + * immediate. Consider using {@link #listTables(java.lang.String)} and + * {@link #disableTable(byte[])} + * + * @param regex The regular expression to match table names against + * @param force When true, force change of the table state in ZK + * @return Table descriptors for tables that couldn't be disabled + * @throws IOException + * @see #disableTables(java.util.regex.Pattern) + * @see #disableTable(java.lang.String) + */ + public HTableDescriptor[] disableTables(String regex, final boolean force) + throws IOException { + return disableTables(Pattern.compile(regex), force); } /** @@ -874,11 +978,28 @@ public class HBaseAdmin implements Abortable, Closeable { * @throws IOException */ public HTableDescriptor[] disableTables(Pattern pattern) throws IOException { + return disableTables(pattern, false); + } + + /** + * Disable tables matching the passed in pattern and wait on completion. + * + * Warning: Use this method carefully, there is no prompting and the effect is + * immediate. Consider using {@link #listTables(java.util.regex.Pattern) } and + * {@link #disableTable(byte[])} + * + * @param pattern The pattern to match table names against + * @param force When true, force change of the table state in ZK + * @return Table descriptors for tables that couldn't be disabled + * @throws IOException + */ + public HTableDescriptor[] disableTables(Pattern pattern, final boolean force) + throws IOException { List failed = new LinkedList(); for (HTableDescriptor table : listTables(pattern)) { if (isTableEnabled(table.getName())) { try { - disableTable(table.getName()); + disableTable(table.getName(), force); } catch (IOException ex) { LOG.info("Failed to disable table " + table.getNameAsString(), ex); failed.add(table); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java index 6937d63..fcdd907 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java @@ -168,45 +168,49 @@ public class BaseMasterObserver implements MasterObserver { @Override public void preEnableTable(ObserverContext ctx, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { } @Override public void postEnableTable(ObserverContext ctx, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { } @Override public void preEnableTableHandler( - ObserverContext ctx, byte[] tableName) + ObserverContext ctx, byte[] tableName, + boolean skipTableStateCheck) throws IOException { } @Override public void postEnableTableHandler( - ObserverContext ctx, byte[] tableName) + ObserverContext ctx, byte[] tableName, + boolean skipTableStateCheck) throws IOException { } @Override public void preDisableTable(ObserverContext ctx, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { } @Override public void postDisableTable(ObserverContext ctx, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { } @Override public void preDisableTableHandler( - ObserverContext ctx, byte[] tableName) + ObserverContext ctx, byte[] tableName, + boolean skipTableStateCheck) throws IOException { } @Override public void postDisableTableHandler( - ObserverContext ctx, byte[] tableName) + ObserverContext ctx, byte[] tableName, + boolean skipTableStateCheck) throws IOException { } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java index 515c4bf..42c3bb2 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java @@ -301,18 +301,22 @@ public interface MasterObserver extends Coprocessor { * It can't bypass the default action, e.g., ctx.bypass() won't have effect. * @param ctx the environment to interact with the framework and master * @param tableName the name of the table + * @param skipTableStateCheck flag to skip table status check, + * default false */ void preEnableTable(final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called after the enableTable operation has been requested. Called as part * of enable table RPC call. * @param ctx the environment to interact with the framework and master * @param tableName the name of the table + * @param skipTableStateCheck flag to skip table status check, + * default false */ void postEnableTable(final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called prior to enabling a table. Called as part of enable table handler @@ -320,20 +324,24 @@ public interface MasterObserver extends Coprocessor { * It can't bypass the default action, e.g., ctx.bypass() won't have effect. * @param ctx the environment to interact with the framework and master * @param tableName the name of the table + * @param skipTableStateCheck flag to skip table status check, + * default false */ void preEnableTableHandler( final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called after the enableTable operation has been requested. Called as part * of enable table handler and it is async to the enable table RPC call. * @param ctx the environment to interact with the framework and master * @param tableName the name of the table + * @param skipTableStateCheck flag to skip table status check, + * default false */ void postEnableTableHandler( final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called prior to disabling a table. Called as part of disable table RPC @@ -343,7 +351,7 @@ public interface MasterObserver extends Coprocessor { * @param tableName the name of the table */ void preDisableTable(final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called after the disableTable operation has been requested. Called as part @@ -352,7 +360,7 @@ public interface MasterObserver extends Coprocessor { * @param tableName the name of the table */ void postDisableTable(final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called prior to disabling a table. Called as part of disable table handler @@ -363,7 +371,7 @@ public interface MasterObserver extends Coprocessor { */ void preDisableTableHandler( final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called after the disableTable operation has been requested. Called as part @@ -373,7 +381,7 @@ public interface MasterObserver extends Coprocessor { */ void postDisableTableHandler( final ObserverContext ctx, - final byte[] tableName) throws IOException; + final byte[] tableName, boolean skipTableStateCheck) throws IOException; /** * Called prior to moving a given region from one region server to another. diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 0c428f3..1702f15 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -1672,16 +1672,17 @@ Server { public EnableTableResponse enableTable(RpcController controller, EnableTableRequest request) throws ServiceException { byte [] tableName = request.getTableName().toByteArray(); + boolean skipTableStateCheck = request.getForce(); try { checkInitialized(); if (cpHost != null) { - cpHost.preEnableTable(tableName); + cpHost.preEnableTable(tableName, skipTableStateCheck); } this.executorService.submit(new EnableTableHandler(this, tableName, - catalogTracker, assignmentManager, false)); + catalogTracker, assignmentManager, skipTableStateCheck)); if (cpHost != null) { - cpHost.postEnableTable(tableName); + cpHost.postEnableTable(tableName, skipTableStateCheck); } } catch (IOException ioe) { throw new ServiceException(ioe); @@ -1693,16 +1694,17 @@ Server { public DisableTableResponse disableTable(RpcController controller, DisableTableRequest request) throws ServiceException { byte [] tableName = request.getTableName().toByteArray(); + boolean skipTableStateCheck = request.getForce(); try { checkInitialized(); if (cpHost != null) { - cpHost.preDisableTable(tableName); + cpHost.preDisableTable(tableName, skipTableStateCheck); } this.executorService.submit(new DisableTableHandler(this, tableName, - catalogTracker, assignmentManager, false)); + catalogTracker, assignmentManager, skipTableStateCheck)); if (cpHost != null) { - cpHost.postDisableTable(tableName); + cpHost.postDisableTable(tableName, skipTableStateCheck); } } catch (IOException ioe) { throw new ServiceException(ioe); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index 6548963..a215d10 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -547,13 +547,15 @@ public class MasterCoprocessorHost } } - public void preEnableTable(final byte [] tableName) throws IOException { + public void preEnableTable(final byte [] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env: coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { - ((MasterObserver)env.getInstance()).preEnableTable(ctx, tableName); + ((MasterObserver)env.getInstance()).preEnableTable(ctx, tableName, + skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } @@ -564,13 +566,15 @@ public class MasterCoprocessorHost } } - public void postEnableTable(final byte [] tableName) throws IOException { + public void postEnableTable(final byte [] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env: coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { - ((MasterObserver)env.getInstance()).postEnableTable(ctx, tableName); + ((MasterObserver)env.getInstance()).postEnableTable(ctx, tableName, + skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } @@ -581,14 +585,15 @@ public class MasterCoprocessorHost } } - public void preEnableTableHandler(final byte[] tableName) throws IOException { + public void preEnableTableHandler(final byte[] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env : coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { ((MasterObserver) env.getInstance()).preEnableTableHandler(ctx, - tableName); + tableName, skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } @@ -599,14 +604,15 @@ public class MasterCoprocessorHost } } - public void postEnableTableHandler(final byte[] tableName) throws IOException { + public void postEnableTableHandler(final byte[] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env : coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { ((MasterObserver) env.getInstance()).postEnableTableHandler(ctx, - tableName); + tableName, skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } @@ -617,13 +623,15 @@ public class MasterCoprocessorHost } } - public void preDisableTable(final byte [] tableName) throws IOException { + public void preDisableTable(final byte [] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env: coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { - ((MasterObserver)env.getInstance()).preDisableTable(ctx, tableName); + ((MasterObserver)env.getInstance()).preDisableTable(ctx, tableName, + skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } @@ -634,13 +642,15 @@ public class MasterCoprocessorHost } } - public void postDisableTable(final byte [] tableName) throws IOException { + public void postDisableTable(final byte [] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env: coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { - ((MasterObserver)env.getInstance()).postDisableTable(ctx, tableName); + ((MasterObserver)env.getInstance()).postDisableTable(ctx, tableName, + skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } @@ -651,14 +661,15 @@ public class MasterCoprocessorHost } } - public void preDisableTableHandler(final byte[] tableName) throws IOException { + public void preDisableTableHandler(final byte[] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env : coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { ((MasterObserver) env.getInstance()).preDisableTableHandler(ctx, - tableName); + tableName, skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } @@ -669,15 +680,15 @@ public class MasterCoprocessorHost } } - public void postDisableTableHandler(final byte[] tableName) - throws IOException { + public void postDisableTableHandler(final byte[] tableName, final boolean skipTableStateCheck) + throws IOException { ObserverContext ctx = null; for (MasterEnvironment env : coprocessors) { if (env.getInstance() instanceof MasterObserver) { ctx = ObserverContext.createAndPrepare(env, ctx); try { ((MasterObserver) env.getInstance()).postDisableTableHandler(ctx, - tableName); + tableName, skipTableStateCheck); } catch (Throwable e) { handleCoprocessorThrowable(env, e); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java index 3a6b629..0cec67e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java @@ -50,6 +50,7 @@ public class DisableTableHandler extends EventHandler { private final byte [] tableName; private final String tableNameStr; private final AssignmentManager assignmentManager; + private boolean skipTableStateCheck = false; public DisableTableHandler(Server server, byte [] tableName, CatalogTracker catalogTracker, AssignmentManager assignmentManager, @@ -59,6 +60,7 @@ public class DisableTableHandler extends EventHandler { this.tableName = tableName; this.tableNameStr = Bytes.toString(this.tableName); this.assignmentManager = assignmentManager; + this.skipTableStateCheck = skipTableStateCheck; // Check if table exists // TODO: do we want to keep this in-memory as well? i guess this is // part of old master rewrite, schema to zk to check for table @@ -71,8 +73,7 @@ public class DisableTableHandler extends EventHandler { // the table at the same time. Ensure only the first request is honored // After that, no other requests can be accepted until the table reaches // DISABLED or ENABLED. - if (!skipTableStateCheck) - { + if (!skipTableStateCheck) { try { if (!this.assignmentManager.getZKTable().checkEnabledAndSetDisablingTable (this.tableNameStr)) { @@ -103,11 +104,11 @@ public class DisableTableHandler extends EventHandler { MasterCoprocessorHost cpHost = ((HMaster) this.server) .getCoprocessorHost(); if (cpHost != null) { - cpHost.preDisableTableHandler(this.tableName); + cpHost.preDisableTableHandler(this.tableName, this.skipTableStateCheck); } handleDisableTable(); if (cpHost != null) { - cpHost.postDisableTableHandler(this.tableName); + cpHost.postDisableTableHandler(this.tableName, this.skipTableStateCheck); } } catch (IOException e) { LOG.error("Error trying to disable table " + this.tableNameStr, e); @@ -145,9 +146,22 @@ public class DisableTableHandler extends EventHandler { break; } } - // Flip the table to disabled if success. - if (done) this.assignmentManager.getZKTable().setDisabledTable(this.tableNameStr); - LOG.info("Disabled table is done=" + done); + if (done) { + // Flip the table to disabled if success. + this.assignmentManager.getZKTable().setDisabledTable(this.tableNameStr); + LOG.info(String.format("Table '%s' was successfully disabled. Status: done=%b", + this.tableNameStr, done)); + } else if (this.skipTableStateCheck) { + // we did our best. brute-force ZK state when required. + int onlineRegions = this.assignmentManager + .getRegionStates().getRegionsOfTable(tableName).size(); + this.assignmentManager.getZKTable().setDisabledTable(this.tableNameStr); + LOG.warn(String.format("Table '%s' was NOT disabled but ZK state forced anyway." + + " OnlineRegions: %d Status: done=%b", onlineRegions, done)); + } else { + LOG.warn(String.format("Table '%s' was NOT disabled. Status: done=%b", + this.tableNameStr, done)); + } } /** diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java index f46c870..7af0d36 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java @@ -56,7 +56,7 @@ public class EnableTableHandler extends EventHandler { private final String tableNameStr; private final AssignmentManager assignmentManager; private final CatalogTracker ct; - private boolean retainAssignment = false; + private boolean skipTableStateCheck = false; public EnableTableHandler(Server server, byte [] tableName, CatalogTracker catalogTracker, AssignmentManager assignmentManager, @@ -67,7 +67,7 @@ public class EnableTableHandler extends EventHandler { this.tableNameStr = Bytes.toString(tableName); this.ct = catalogTracker; this.assignmentManager = assignmentManager; - this.retainAssignment = skipTableStateCheck; + this.skipTableStateCheck = skipTableStateCheck; // Check if table exists if (!MetaReader.tableExists(catalogTracker, this.tableNameStr)) { throw new TableNotFoundException(Bytes.toString(tableName)); @@ -77,8 +77,7 @@ public class EnableTableHandler extends EventHandler { // the table at the same time. Ensure only the first request is honored // After that, no other requests can be accepted until the table reaches // DISABLED or ENABLED. - if (!skipTableStateCheck) - { + if (!skipTableStateCheck) { try { if (!this.assignmentManager.getZKTable().checkDisabledAndSetEnablingTable (this.tableNameStr)) { @@ -109,11 +108,11 @@ public class EnableTableHandler extends EventHandler { MasterCoprocessorHost cpHost = ((HMaster) this.server) .getCoprocessorHost(); if (cpHost != null) { - cpHost.preEnableTableHandler(this.tableName); + cpHost.preEnableTableHandler(this.tableName, this.skipTableStateCheck); } handleEnableTable(); if (cpHost != null) { - cpHost.postEnableTableHandler(this.tableName); + cpHost.postEnableTableHandler(this.tableName, this.skipTableStateCheck); } } catch (IOException e) { LOG.error("Error trying to enable the table " + this.tableNameStr, e); @@ -144,7 +143,7 @@ public class EnableTableHandler extends EventHandler { LOG.info("Table '" + this.tableNameStr + "' has " + countOfRegionsInTable + " regions, of which " + regionsCount + " are offline."); BulkEnabler bd = new BulkEnabler(this.server, regions, countOfRegionsInTable, - this.retainAssignment); + this.skipTableStateCheck); try { if (bd.bulkAssign()) { done = true; @@ -157,13 +156,19 @@ public class EnableTableHandler extends EventHandler { } if (done) { // Flip the table to enabled. - this.assignmentManager.getZKTable().setEnabledTable( - this.tableNameStr); - LOG.info("Table '" + this.tableNameStr - + "' was successfully enabled. Status: done=" + done); + this.assignmentManager.getZKTable().setEnabledTable(this.tableNameStr); + LOG.info(String.format("Table '%s' was successfully enabled. Status: done=%b", + this.tableNameStr, done)); + } else if (this.skipTableStateCheck) { + // we did our best. brute-force ZK state when required. + int onlineRegions = this.assignmentManager + .getRegionStates().getRegionsOfTable(tableName).size(); + this.assignmentManager.getZKTable().setEnabledTable(this.tableNameStr); + LOG.warn(String.format("Table '%s' was NOT enabled but ZK state forced anyway." + + " OnlineRegions: %d Status: done=%b", onlineRegions, done)); } else { - LOG.warn("Table '" + this.tableNameStr - + "' wasn't successfully enabled. Status: done=" + done); + LOG.warn(String.format("Table '%s' was NOT enabled. Status: done=%b", + this.tableNameStr, done)); } } @@ -181,14 +186,14 @@ public class EnableTableHandler extends EventHandler { HRegionInfo hri = regionLocation.getFirst(); ServerName sn = regionLocation.getSecond(); if (!regionStates.isRegionInTransition(hri) && !regionStates.isRegionAssigned(hri)) { - if (this.retainAssignment && sn != null && serverManager.isServerOnline(sn)) { + if (this.skipTableStateCheck && sn != null && serverManager.isServerOnline(sn)) { this.assignmentManager.addPlan(hri.getEncodedName(), new RegionPlan(hri, null, sn)); } regions.add(hri); } else { if (LOG.isDebugEnabled()) { LOG.debug("Skipping assign for the region " + hri + " during enable table " - + hri.getTableNameAsString() + " because its already in tranition or assigned."); + + hri.getTableNameAsString() + " because its already in transition or assigned."); } } } @@ -217,7 +222,7 @@ public class EnableTableHandler extends EventHandler { boolean roundRobinAssignment = this.server.getConfiguration().getBoolean( "hbase.master.enabletable.roundrobin", false); - // In case of masterRestart always go with single assign. Going thro + // In case of masterRestart always go with single assign. Going through // roundRobinAssignment will use bulkassign which may lead to double assignment. if (retainAssignment || !roundRobinAssignment) { for (HRegionInfo region : regions) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java index 0218f2e..2e2bbe1 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java @@ -995,9 +995,11 @@ public final class RequestConverter { * @param tableName * @return an EnableTableRequest */ - public static EnableTableRequest buildEnableTableRequest(final byte [] tableName) { + public static EnableTableRequest buildEnableTableRequest( + final byte [] tableName, final boolean force) { EnableTableRequest.Builder builder = EnableTableRequest.newBuilder(); builder.setTableName(ByteString.copyFrom(tableName)); + builder.setForce(force); return builder.build(); } @@ -1007,9 +1009,11 @@ public final class RequestConverter { * @param tableName * @return a DisableTableRequest */ - public static DisableTableRequest buildDisableTableRequest(final byte [] tableName) { + public static DisableTableRequest buildDisableTableRequest( + final byte [] tableName, final boolean force) { DisableTableRequest.Builder builder = DisableTableRequest.newBuilder(); builder.setTableName(ByteString.copyFrom(tableName)); + builder.setForce(force); return builder.build(); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java index 2dd9771..b572d1e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java @@ -655,24 +655,24 @@ public class AccessController extends BaseRegionObserver byte[] tableName, byte[] col) throws IOException {} @Override - public void preEnableTable(ObserverContext c, byte[] tableName) - throws IOException { + public void preEnableTable(ObserverContext c, + byte[] tableName, boolean skipTableStateCheck) throws IOException { requirePermission(tableName, null, null, Action.ADMIN, Action.CREATE); } @Override public void preEnableTableHandler(ObserverContext c, - byte[] tableName) throws IOException {} + byte[] tableName, boolean skipTableStateCheck) throws IOException {} @Override public void postEnableTable(ObserverContext c, - byte[] tableName) throws IOException {} + byte[] tableName, boolean skipTableStateCheck) throws IOException {} @Override public void postEnableTableHandler(ObserverContext c, - byte[] tableName) throws IOException {} + byte[] tableName, boolean skipTableStateCheck) throws IOException {} @Override - public void preDisableTable(ObserverContext c, byte[] tableName) - throws IOException { + public void preDisableTable(ObserverContext c, + byte[] tableName, boolean skipTableStateCheck) throws IOException { if (Bytes.equals(tableName, AccessControlLists.ACL_GLOBAL_NAME)) { throw new AccessDeniedException("Not allowed to disable " + AccessControlLists.ACL_TABLE_NAME_STR + " table."); @@ -682,13 +682,13 @@ public class AccessController extends BaseRegionObserver @Override public void preDisableTableHandler(ObserverContext c, - byte[] tableName) throws IOException {} + byte[] tableName, boolean skipTableStateCheck) throws IOException {} @Override public void postDisableTable(ObserverContext c, - byte[] tableName) throws IOException {} + byte[] tableName, boolean skipTableStateCheck) throws IOException {} @Override public void postDisableTableHandler(ObserverContext c, - byte[] tableName) throws IOException {} + byte[] tableName, boolean skipTableStateCheck) throws IOException {} @Override public void preMove(ObserverContext c, HRegionInfo region, diff --git a/hbase-server/src/main/ruby/hbase/admin.rb b/hbase-server/src/main/ruby/hbase/admin.rb index 3e7b13b..f8f2331 100644 --- a/hbase-server/src/main/ruby/hbase/admin.rb +++ b/hbase-server/src/main/ruby/hbase/admin.rb @@ -125,32 +125,33 @@ module Hbase #---------------------------------------------------------------------------------------------- # Enables a table - def enable(table_name) + def enable(table_name, force) tableExists(table_name) return if enabled?(table_name) - @admin.enableTable(table_name) + @admin.enableTable(table_name, java.lang.Boolean::valueOf(force)) end #---------------------------------------------------------------------------------------------- # Enables all tables matching the given regex - def enable_all(regex) + def enable_all(regex, force) regex = regex.to_s - @admin.enableTables(regex) + @admin.enableTables(regex, java.lang.Boolean::valueOf(force)) end #---------------------------------------------------------------------------------------------- # Disables a table - def disable(table_name) + def disable(table_name, force) tableExists(table_name) return if disabled?(table_name) - @admin.disableTable(table_name) + @admin.disableTable(table_name, java.lang.Boolean::valueOf(force)) end #---------------------------------------------------------------------------------------------- # Disables all tables matching the given regex - def disable_all(regex) + def disable_all(regex, force) regex = regex.to_s - @admin.disableTables(regex).map { |t| t.getNameAsString } + force = java.lang.Boolean::valueOf(force) + @admin.disableTables(regex, force).map { |t| t.getNameAsString } end #--------------------------------------------------------------------------------------------- diff --git a/hbase-server/src/main/ruby/shell/commands/disable.rb b/hbase-server/src/main/ruby/shell/commands/disable.rb index b10aa9b..af1f832 100644 --- a/hbase-server/src/main/ruby/shell/commands/disable.rb +++ b/hbase-server/src/main/ruby/shell/commands/disable.rb @@ -22,13 +22,21 @@ module Shell class Disable < Command def help return <<-EOF -Start disable of named table: e.g. "hbase> disable 't1'" +Start disable of named table. + + hbase> disable 't1' + +Advanced usage: force disablement. This updates/overrides the HMaster +state machine by writing disablement directly to ZK. Use when performing +online table surgery, ie, `hbase hbck -fix`. + + hbase> disable 't1', true EOF end - def command(table) + def command(table, force = 'false') format_simple_command do - admin.disable(table) + admin.disable(table, force) end end end diff --git a/hbase-server/src/main/ruby/shell/commands/disable_all.rb b/hbase-server/src/main/ruby/shell/commands/disable_all.rb index 0e7c30e..748bb1f 100644 --- a/hbase-server/src/main/ruby/shell/commands/disable_all.rb +++ b/hbase-server/src/main/ruby/shell/commands/disable_all.rb @@ -22,13 +22,15 @@ module Shell class DisableAll < Command def help return <<-EOF -Disable all of tables matching the given regex: +Disable all of the tables matching the given regex. Optionally +force disablement. See 'disable' command for details. -hbase> disable_all 't.*' + hbase> disable_all 't.*' + hbase> disable_all 't.*', true EOF end - def command(regex) + def command(regex, force = 'false') regex = /^#{regex}$/ unless regex.is_a?(Regexp) list = admin.list.grep(regex) count = list.size @@ -40,7 +42,7 @@ EOF answer = gets.chomp unless count == 0 puts "No tables matched the regex #{regex.to_s}" if count == 0 return unless answer =~ /y.*/i - failed = admin.disable_all(regex) + failed = admin.disable_all(regex, force) puts "#{count - failed.size} tables successfully disabled" puts "#{failed.size} tables not disabled due to an exception: #{failed.join ','}" unless failed.size == 0 end diff --git a/hbase-server/src/main/ruby/shell/commands/enable.rb b/hbase-server/src/main/ruby/shell/commands/enable.rb index a4d495a..fb71294 100644 --- a/hbase-server/src/main/ruby/shell/commands/enable.rb +++ b/hbase-server/src/main/ruby/shell/commands/enable.rb @@ -22,13 +22,21 @@ module Shell class Enable < Command def help return <<-EOF -Start enable of named table: e.g. "hbase> enable 't1'" +Start enable of named table. + + hbase> enable 't1' + +Advanced usage: force enablement. This updates/overrides the HMaster +state machine by writing enablement directly to ZK. Use when performing +online table surgery, ie, `hbase hbck -fix`. + + hbase> enable 't1', true EOF end - def command(table) + def command(table, force = 'false') format_simple_command do - admin.enable(table) + admin.enable(table, force) end end end diff --git a/hbase-server/src/main/ruby/shell/commands/enable_all.rb b/hbase-server/src/main/ruby/shell/commands/enable_all.rb index fc0f081..a131bfa 100644 --- a/hbase-server/src/main/ruby/shell/commands/enable_all.rb +++ b/hbase-server/src/main/ruby/shell/commands/enable_all.rb @@ -22,13 +22,15 @@ module Shell class EnableAll < Command def help return <<-EOF -Enable all of the tables matching the given regex: +Enable all of the tables matching the given regex. Optionally +force enablement. See 'enable' command for details. -hbase> enable_all 't.*' + hbase> enable_all 't.*' + hbase> enable_all 't.*', true EOF end - def command(regex) + def command(regex, force = 'false') regex = /^#{regex}$/ unless regex.is_a?(Regexp) list = admin.list.grep(regex) count = list.size @@ -40,7 +42,7 @@ EOF answer = gets.chomp unless count == 0 puts "No tables matched the regex #{regex.to_s}" if count == 0 return unless answer =~ /y.*/i - failed = admin.enable_all(regex) + failed = admin.enable_all(regex, force) puts "#{count - failed.size} tables successfully enabled" puts "#{failed.size} tables not enabled due to an exception: #{failed.join ','}" unless failed.size == 0 end diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java index aa862a4..faa76e1 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java @@ -38,7 +38,24 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.*; +import org.apache.hadoop.hbase.DoNotRetryIOException; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HRegionLocation; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.InvalidFamilyOperationException; +import org.apache.hadoop.hbase.LargeTests; +import org.apache.hadoop.hbase.MasterNotRunningException; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.NotServingRegionException; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.TableExistsException; +import org.apache.hadoop.hbase.TableNotDisabledException; +import org.apache.hadoop.hbase.TableNotEnabledException; +import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.catalog.CatalogTracker; import org.apache.hadoop.hbase.executor.EventHandler; import org.apache.hadoop.hbase.executor.EventHandler.EventType; @@ -50,12 +67,17 @@ import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.regionserver.wal.HLogUtilsForTests; -import org.apache.hadoop.hbase.InvalidFamilyOperationException; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly; import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; -import org.junit.*; +import org.apache.zookeeper.KeeperException; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; import org.junit.experimental.categories.Category; import com.google.protobuf.ServiceException; @@ -256,6 +278,52 @@ public class TestAdmin { ok = false; } assertTrue(ok); + + // Test forceful table disable + try { + TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().getZKTable() + .setDisablingTable(Bytes.toString(table)); + assertTrue("Table must be set to a transitional state.", TEST_UTIL.getHBaseCluster() + .getMaster().getAssignmentManager().getZKTable().isDisablingTable(Bytes.toString(table))); + } catch (KeeperException e) { + fail("Failed to prepare ZooKeeper state."); + } + this.admin.disableTable(table, true); + assertTrue("Table must be disabled.", TEST_UTIL.getHBaseCluster().getMaster() + .getAssignmentManager().getZKTable().isDisabledTable(Bytes.toString(table))); + + // Verify that table is disabled + get = new Get(row); + get.addColumn(HConstants.CATALOG_FAMILY, qualifier); + ok = false; + try { + ht.get(get); + } catch (DoNotRetryIOException e) { + ok = true; + } + assertTrue(ok); + + // Test forceful table enable + try { + TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().getZKTable() + .setEnablingTable(Bytes.toString(table)); + assertTrue("Table must be set to a transitional state.", TEST_UTIL.getHBaseCluster() + .getMaster().getAssignmentManager().getZKTable().isEnablingTable(Bytes.toString(table))); + } catch (KeeperException e) { + fail("Failed to prepare ZooKeeper state."); + } + this.admin.enableTable(table, true); + assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster().getMaster() + .getAssignmentManager().getZKTable().isEnabledTable(Bytes.toString(table))); + + // Verify that table is enabled + try { + ht.get(get); + } catch (RetriesExhaustedException e) { + ok = false; + } + assertTrue(ok); + ht.close(); } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java index dd099fb..93e948d 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java @@ -309,7 +309,7 @@ public class TestMasterObserver { @Override public void preEnableTable(ObserverContext env, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { if (bypass) { env.bypass(); } @@ -318,7 +318,7 @@ public class TestMasterObserver { @Override public void postEnableTable(ObserverContext env, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { postEnableTableCalled = true; } @@ -332,7 +332,7 @@ public class TestMasterObserver { @Override public void preDisableTable(ObserverContext env, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { if (bypass) { env.bypass(); } @@ -341,7 +341,7 @@ public class TestMasterObserver { @Override public void postDisableTable(ObserverContext env, - byte[] tableName) throws IOException { + byte[] tableName, boolean skipTableStateCheck) throws IOException { postDisableTableCalled = true; } @@ -660,8 +660,8 @@ public class TestMasterObserver { @Override public void preEnableTableHandler( - ObserverContext env, byte[] tableName) - throws IOException { + ObserverContext env, byte[] tableName, + boolean skipTableStateCheck) throws IOException { if (bypass) { env.bypass(); } @@ -670,8 +670,8 @@ public class TestMasterObserver { @Override public void postEnableTableHandler( - ObserverContext ctx, byte[] tableName) - throws IOException { + ObserverContext ctx, byte[] tableName, + boolean skipTableStateCheck) throws IOException { postEnableTableHandlerCalled = true; } @@ -685,7 +685,8 @@ public class TestMasterObserver { @Override public void preDisableTableHandler( - ObserverContext env, byte[] tableName) + ObserverContext env, byte[] tableName, + boolean skipTableStateCheck) throws IOException { if (bypass) { env.bypass(); @@ -695,7 +696,8 @@ public class TestMasterObserver { @Override public void postDisableTableHandler( - ObserverContext ctx, byte[] tableName) + ObserverContext ctx, byte[] tableName, + boolean skipTableStateCheck) throws IOException { postDisableTableHandlerCalled = true; } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java index d1affa7..429eba9 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java @@ -346,7 +346,7 @@ public class TestAccessController { PrivilegedExceptionAction disableTable = new PrivilegedExceptionAction() { public Object run() throws Exception { ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null), - TEST_TABLE); + TEST_TABLE, false); return null; } }; @@ -354,7 +354,7 @@ public class TestAccessController { PrivilegedExceptionAction disableAclTable = new PrivilegedExceptionAction() { public Object run() throws Exception { ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null), - AccessControlLists.ACL_TABLE_NAME); + AccessControlLists.ACL_TABLE_NAME, false); return null; } }; @@ -371,7 +371,7 @@ public class TestAccessController { PrivilegedExceptionAction enableTable = new PrivilegedExceptionAction() { public Object run() throws Exception { ACCESS_CONTROLLER - .preEnableTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE); + .preEnableTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE, false); return null; } };