diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/ProcedureInfo.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/ProcedureInfo.java index fca2eac..dc7f549 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/ProcedureInfo.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/ProcedureInfo.java @@ -27,8 +27,10 @@ import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos; import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.util.ByteStringer; +import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; import org.apache.hadoop.hbase.util.ForeignExceptionUtil; import org.apache.hadoop.hbase.util.NonceKey; +import org.apache.hadoop.util.StringUtils; /** * Procedure information @@ -164,7 +166,7 @@ public class ProcedureInfo implements Cloneable { @InterfaceAudience.Private public boolean hasClientAckTime() { - return clientAckTime > 0; + return clientAckTime != -1; } @InterfaceAudience.Private @@ -177,6 +179,40 @@ public class ProcedureInfo implements Cloneable { this.clientAckTime = timestamp; } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(procName); + builder.append('('); + builder.append("procId="); + builder.append(procId); + if (hasParentId()) { + builder.append(", parentId="); + builder.append(parentId); + } + if (procOwner != null) { + builder.append(", owner="); + builder.append(procOwner); + } + builder.append(", state="); + builder.append(procState); + + long now = EnvironmentEdgeManager.currentTime(); + builder.append(", startTime="); + builder.append(StringUtils.formatTime(now - startTime)); + builder.append(", lastUpdate="); + builder.append(StringUtils.formatTime(now - startTime)); + + if (isFailed()) { + builder.append(", exception=\""); + builder.append(getExceptionMessage()); + builder.append('"'); + } + + builder.append(')'); + return builder.toString(); + } + /** * @return Convert the current {@link ProcedureInfo} into a Protocol Buffers Procedure * instance. diff --git a/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/Procedure.java b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/Procedure.java index b512379..3242b29 100644 --- a/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/Procedure.java +++ b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/Procedure.java @@ -193,6 +193,19 @@ public abstract class Procedure implements Comparable { return false; } + /** + * By default, the executor will keep the procedure result around util + * the eviction TTL is expired. The client can cut down the waiting time + * by requesting that the result is removed from the executor. + * In case of system started procedure, we can force the executor to auto-ack. + * @param env the environment passed to the ProcedureExecutor + * @param true if the executor should wait the client ack for the result. + * Defaults to return true. + */ + protected boolean shouldWaitClientAck(final TEnvironment env) { + return true; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureExecutor.java b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureExecutor.java index 74d28d7..50eca71 100644 --- a/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureExecutor.java +++ b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureExecutor.java @@ -165,22 +165,23 @@ public class ProcedureExecutor { final long evictTtl = conf.getInt(EVICT_TTL_CONF_KEY, DEFAULT_EVICT_TTL); final long evictAckTtl = conf.getInt(EVICT_ACKED_TTL_CONF_KEY, DEFAULT_ACKED_EVICT_TTL); - long now = EnvironmentEdgeManager.currentTime(); - Iterator> it = completed.entrySet().iterator(); + final long now = EnvironmentEdgeManager.currentTime(); + final Iterator> it = completed.entrySet().iterator(); + final boolean isDebugEnabled = LOG.isDebugEnabled(); while (it.hasNext() && store.isRunning()) { - Map.Entry entry = it.next(); - ProcedureInfo result = entry.getValue(); + final Map.Entry entry = it.next(); + final ProcedureInfo procInfo = entry.getValue(); // TODO: Select TTL based on Procedure type - if ((result.hasClientAckTime() && (now - result.getClientAckTime()) >= evictAckTtl) || - (now - result.getLastUpdate()) >= evictTtl) { - if (LOG.isDebugEnabled()) { - LOG.debug("Evict completed procedure " + entry.getKey()); + if ((procInfo.hasClientAckTime() && (now - procInfo.getClientAckTime()) >= evictAckTtl) || + (now - procInfo.getLastUpdate()) >= evictTtl) { + if (isDebugEnabled) { + LOG.debug("Evict completed procedure: " + procInfo); } store.delete(entry.getKey()); it.remove(); - NonceKey nonceKey = result.getNonceKey(); + NonceKey nonceKey = procInfo.getNonceKey(); if (nonceKey != null) { nonceKeysToProcIdsMap.remove(nonceKey); } @@ -1259,7 +1260,12 @@ public class ProcedureExecutor { } // update the executor internal state maps - completed.put(proc.getProcId(), Procedure.createProcedureInfo(proc, proc.getNonceKey())); + ProcedureInfo procInfo = Procedure.createProcedureInfo(proc, proc.getNonceKey()); + if (!proc.shouldWaitClientAck(getEnvironment())) { + procInfo.setClientAckTime(0); + } + + completed.put(procInfo.getProcId(), procInfo); rollbackStack.remove(proc.getProcId()); procedures.remove(proc.getProcId()); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java index a760aa2..d8daab7 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java @@ -194,16 +194,18 @@ public class CreateNamespaceProcedure sb.append(")"); } + private boolean isBootstrapNamespace() { + return nsDescriptor.equals(NamespaceDescriptor.DEFAULT_NAMESPACE) || + nsDescriptor.equals(NamespaceDescriptor.SYSTEM_NAMESPACE); + } + @Override protected boolean acquireLock(final MasterProcedureEnv env) { if (!env.getMasterServices().isInitialized()) { // Namespace manager might not be ready if master is not fully initialized, // return false to reject user namespace creation; return true for default // and system namespace creation (this is part of master initialization). - boolean isBootstrapNs = nsDescriptor.equals(NamespaceDescriptor.DEFAULT_NAMESPACE) || - nsDescriptor.equals(NamespaceDescriptor.SYSTEM_NAMESPACE); - - if (!isBootstrapNs && env.waitInitialized(this)) { + if (!isBootstrapNamespace() && env.waitInitialized(this)) { return false; } } @@ -364,4 +366,11 @@ public class CreateNamespaceProcedure } return traceEnabled; } + + @Override + protected boolean shouldWaitClientAck(MasterProcedureEnv env) { + // hbase and default namespaces are created on bootstrap internally by the system + // the client does not know about this procedures. + return !isBootstrapNamespace(); + } } \ No newline at end of file diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java index 1ad8bd5..183871d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java @@ -448,4 +448,11 @@ public class CreateTableProcedure final TableName tableName) throws IOException { env.getMasterServices().getTableDescriptors().get(tableName); } + + @Override + protected boolean shouldWaitClientAck(MasterProcedureEnv env) { + // system tables are created on bootstrap internally by the system + // the client does not know about this procedures. + return !getTableName().isSystemTable(); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java index c5deb0d..19e05fd 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java @@ -767,4 +767,11 @@ implements ServerProcedureInterface { protected boolean isYieldBeforeExecuteFromState(MasterProcedureEnv env, ServerCrashState state) { return true; } + + @Override + protected boolean shouldWaitClientAck(MasterProcedureEnv env) { + // The operation is triggered internally on the server + // the client does not know about this procedure. + return false; + } }