commit 6c627496f3110bd19e7c6970b1a13d819f10a9e9 Author: Michael Stack Date: Tue Dec 27 11:40:58 2016 -0800 Backport. Currently at HMaster. HMaster needs HBASE-16618a which is not in branch-1. diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/coprocessor/BypassCoprocessorException.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/coprocessor/BypassCoprocessorException.java new file mode 100644 index 0000000..3b01a9e --- /dev/null +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/coprocessor/BypassCoprocessorException.java @@ -0,0 +1,44 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.coprocessor; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.classification.InterfaceStability; + +/** + * Thrown if a coprocessor rules we should bypass an operation + */ +@InterfaceAudience.Public +@InterfaceStability.Evolving +public class BypassCoprocessorException extends CoprocessorException { + private static final long serialVersionUID = 5943889011582357043L; + + /** Default Constructor */ + public BypassCoprocessorException() { + super(); + } + + /** + * Constructs the exception and supplies a string as the message + * @param s - message + */ + public BypassCoprocessorException(String s) { + super(s); + } +} \ No newline at end of file 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 939002c..ad4c566 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 @@ -126,7 +126,7 @@ public class ProcedureInfo implements Cloneable { return procName; } - private boolean hasOwner() { + public boolean hasOwner() { return procOwner != null; } @@ -296,4 +296,4 @@ public class ProcedureInfo implements Cloneable { } return procOwner.equals(user.getShortName()); } -} \ No newline at end of file +} diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/ProcedureState.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/ProcedureState.java new file mode 100644 index 0000000..306d285 --- /dev/null +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/ProcedureState.java @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.classification.InterfaceStability; + +/** + * POJO representing Procedure State + */ +@InterfaceAudience.Public +@InterfaceStability.Evolving +public enum ProcedureState { + INITIALIZING, RUNNABLE, WAITING, WAITING_TIMEOUT, ROLLEDBACK, FINISHED; +} diff --git a/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/BadProcedureException.java b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/BadProcedureException.java new file mode 100644 index 0000000..bff0b4a --- /dev/null +++ b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/BadProcedureException.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.procedure2; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.classification.InterfaceStability; +import org.apache.hadoop.hbase.HBaseIOException; + +@InterfaceAudience.Private +@InterfaceStability.Stable +public class BadProcedureException extends HBaseIOException { + public BadProcedureException() { + super(); + } + + public BadProcedureException(String message) { + super(message); + } + + public BadProcedureException(String message, Throwable cause) { + super(message, cause); + } + + public BadProcedureException(Throwable cause) { + super(cause); + } +} 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 51bf9e2..3cf8953 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 @@ -537,7 +537,7 @@ public abstract class Procedure implements Comparable { * Called on store load to initialize the Procedure internals after * the creation/deserialization. */ - private synchronized void setLastUpdate(final long lastUpdate) { + protected synchronized void setLastUpdate(final long lastUpdate) { this.lastUpdate = lastUpdate; } 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 d6ed207..e5395ae 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 @@ -18,9 +18,6 @@ package org.apache.hadoop.hbase.procedure2; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; - import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -29,13 +26,13 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -53,8 +50,13 @@ import org.apache.hadoop.hbase.procedure2.util.TimeoutBlockingQueue.TimeoutRetri import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState; import org.apache.hadoop.hbase.security.User; 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.hbase.util.Pair; +import org.apache.hadoop.hbase.util.Threads; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; /** * Thread Pool that executes the submitted procedures. @@ -609,13 +611,110 @@ public class ProcedureExecutor { return waitingTimeout.remove(chore); } + // ========================================================================== + // Nonce Procedure helpers + // ========================================================================== + /** + * Create a NoneKey from the specified nonceGroup and nonce. + * @param nonceGroup + * @param nonce + * @return the generated NonceKey + */ + public NonceKey createNonceKey(final long nonceGroup, final long nonce) { + return (nonce == HConstants.NO_NONCE) ? null : new NonceKey(nonceGroup, nonce); + } + + /** + * Register a nonce for a procedure that is going to be submitted. + * A procId will be reserved and on submitProcedure(), + * the procedure with the specified nonce will take the reserved ProcId. + * If someone already reserved the nonce, this method will return the procId reserved, + * otherwise an invalid procId will be returned. and the caller should procede + * and submit the procedure. + * + * @param nonceKey A unique identifier for this operation from the client or process. + * @return the procId associated with the nonce, if any otherwise an invalid procId. + */ + public long registerNonce(final NonceKey nonceKey) { + if (nonceKey == null) return -1; + + // check if we have already a Reserved ID for the nonce + Long oldProcId = nonceKeysToProcIdsMap.get(nonceKey); + if (oldProcId == null) { + // reserve a new Procedure ID, this will be associated with the nonce + // and the procedure submitted with the specified nonce will use this ID. + final long newProcId = nextProcId(); + oldProcId = nonceKeysToProcIdsMap.putIfAbsent(nonceKey, newProcId); + if (oldProcId == null) return -1; + } + + // we found a registered nonce, but the procedure may not have been submitted yet. + // since the client expect the procedure to be submitted, spin here until it is. + final boolean isTraceEnabled = LOG.isTraceEnabled(); + while (isRunning() && + !(procedures.containsKey(oldProcId) || completed.containsKey(oldProcId)) && + nonceKeysToProcIdsMap.containsKey(nonceKey)) { + if (isTraceEnabled) { + LOG.trace("waiting for procId=" + oldProcId.longValue() + " to be submitted"); + } + Threads.sleep(100); + } + return oldProcId.longValue(); + } + + /** + * Remove the NonceKey if the procedure was not submitted to the executor. + * @param nonceKey A unique identifier for this operation from the client or process. + */ + public void unregisterNonceIfProcedureWasNotSubmitted(final NonceKey nonceKey) { + if (nonceKey == null) return; + + final Long procId = nonceKeysToProcIdsMap.get(nonceKey); + if (procId == null) return; + + // if the procedure was not submitted, remove the nonce + if (!(procedures.containsKey(procId) || completed.containsKey(procId))) { + nonceKeysToProcIdsMap.remove(nonceKey); + } + } + + /** + * If the failure failed before submitting it, we may want to give back the + * same error to the requests with the same nonceKey. + * + * @param nonceKey A unique identifier for this operation from the client or process + * @param procName name of the procedure, used to inform the user + * @param procOwner name of the owner of the procedure, used to inform the user + * @param exception the failure to report to the user + */ + public void setFailureResultForNonce(final NonceKey nonceKey, final String procName, + final User procOwner, final IOException exception) { + if (nonceKey == null) return; + + final Long procId = nonceKeysToProcIdsMap.get(nonceKey); + if (procId == null || completed.containsKey(procId)) return; + + final long currentTime = EnvironmentEdgeManager.currentTime(); + final ProcedureInfo result = new ProcedureInfo(procId.longValue(), + procName, procOwner != null ? procOwner.getShortName() : null, + ProcedureState.ROLLEDBACK, + -1, nonceKey, + ForeignExceptionUtil.toProtoForeignException("ProcedureExecutor", exception), + currentTime, currentTime, null); + completed.putIfAbsent(procId, result); + } + + // ========================================================================== + // Submit/Abort Procedure + // ========================================================================== + /** * Add a new root-procedure to the executor. * @param proc the new procedure to execute. * @return the procedure id, that can be used to monitor the operation */ public long submitProcedure(final Procedure proc) { - return submitProcedure(proc, HConstants.NO_NONCE, HConstants.NO_NONCE); + return submitProcedure(proc, null); } /** @@ -625,43 +724,27 @@ public class ProcedureExecutor { * @param nonce * @return the procedure id, that can be used to monitor the operation */ - public long submitProcedure( - final Procedure proc, - final long nonceGroup, - final long nonce) { + @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NP_NULL_ON_SOME_PATH", + justification = "FindBugs is blind to the check-for-null") + public long submitProcedure(final Procedure proc, final NonceKey nonceKey) { Preconditions.checkArgument(proc.getState() == ProcedureState.INITIALIZING); Preconditions.checkArgument(isRunning()); Preconditions.checkArgument(lastProcId.get() >= 0); Preconditions.checkArgument(!proc.hasParent()); - Long currentProcId; - - // The following part of the code has to be synchronized to prevent multiple request - // with the same nonce to execute at the same time. - synchronized (this) { - // Check whether the proc exists. If exist, just return the proc id. - // This is to prevent the same proc to submit multiple times (it could happen - // when client could not talk to server and resubmit the same request). - NonceKey noncekey = null; - if (nonce != HConstants.NO_NONCE) { - noncekey = new NonceKey(nonceGroup, nonce); - currentProcId = nonceKeysToProcIdsMap.get(noncekey); - if (currentProcId != null) { - // Found the proc - return currentProcId; - } - } - // Initialize the Procedure ID + final Long currentProcId; + if (nonceKey != null) { + currentProcId = nonceKeysToProcIdsMap.get(nonceKey); + Preconditions.checkArgument(currentProcId != null, + "expected nonceKey=" + nonceKey + " to be reserved, use registerNonce()"); + } else { currentProcId = nextProcId(); - proc.setProcId(currentProcId); + } - // This is new procedure. Set the noncekey and insert into the map. - if (noncekey != null) { - proc.setNonceKey(noncekey); - nonceKeysToProcIdsMap.put(noncekey, currentProcId); - } - } // end of synchronized (this) + // Initialize the procedure + proc.setNonceKey(nonceKey); + proc.setProcId(currentProcId.longValue()); // Commit the transaction store.insert(proc, null); @@ -678,7 +761,7 @@ public class ProcedureExecutor { procedures.put(currentProcId, proc); sendProcedureAddedNotification(currentProcId); runnables.addBack(proc); - return currentProcId; + return proc.getProcId(); } public ProcedureInfo getResult(final long procId) { diff --git a/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureUtil.java b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureUtil.java new file mode 100644 index 0000000..2b80e7b --- /dev/null +++ b/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureUtil.java @@ -0,0 +1,267 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.procedure2; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; + +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.ProcedureInfo; +import org.apache.hadoop.hbase.ProcedureState; +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos; +import org.apache.hadoop.hbase.util.ForeignExceptionUtil; +import org.apache.hadoop.hbase.util.NonceKey; + +import com.google.common.base.Preconditions; +import com.google.protobuf.ByteString; +import com.google.protobuf.HBaseZeroCopyByteString; + + +/** + * Helper to convert to/from ProcedureProtos + */ +@InterfaceAudience.Private +public final class ProcedureUtil { + private ProcedureUtil() { } + + // ========================================================================== + // Reflection helpers to create/validate a Procedure object + // ========================================================================== + public static Procedure newProcedure(final String className) throws BadProcedureException { + try { + final Class clazz = Class.forName(className); + if (!Modifier.isPublic(clazz.getModifiers())) { + throw new Exception("the " + clazz + " class is not public"); + } + + final Constructor ctor = clazz.getConstructor(); + assert ctor != null : "no constructor found"; + if (!Modifier.isPublic(ctor.getModifiers())) { + throw new Exception("the " + clazz + " constructor is not public"); + } + return (Procedure)ctor.newInstance(); + } catch (Exception e) { + throw new BadProcedureException("The procedure class " + className + + " must be accessible and have an empty constructor", e); + } + } + + public static void validateClass(final Procedure proc) throws BadProcedureException { + try { + final Class clazz = proc.getClass(); + if (!Modifier.isPublic(clazz.getModifiers())) { + throw new Exception("the " + clazz + " class is not public"); + } + + final Constructor ctor = clazz.getConstructor(); + assert ctor != null; + if (!Modifier.isPublic(ctor.getModifiers())) { + throw new Exception("the " + clazz + " constructor is not public"); + } + } catch (Exception e) { + throw new BadProcedureException("The procedure class " + proc.getClass().getName() + + " must be accessible and have an empty constructor", e); + } + } + + // ========================================================================== + // convert to and from Procedure object + // ========================================================================== + + /** + * Helper to convert the procedure to protobuf. + * Used by ProcedureStore implementations. + */ + public static ProcedureProtos.Procedure convertToProtoProcedure(final Procedure proc) + throws IOException { + Preconditions.checkArgument(proc != null); + validateClass(proc); + + final ProcedureProtos.Procedure.Builder builder = ProcedureProtos.Procedure.newBuilder() + .setClassName(proc.getClass().getName()) + .setProcId(proc.getProcId()) + .setState(proc.getState()) + .setStartTime(proc.getStartTime()) + .setLastUpdate(proc.getLastUpdate()); + + if (proc.hasParent()) { + builder.setParentId(proc.getParentProcId()); + } + + if (proc.hasTimeout()) { + builder.setTimeout(proc.getTimeout()); + } + + if (proc.hasOwner()) { + builder.setOwner(proc.getOwner()); + } + + final int[] stackIds = proc.getStackIndexes(); + if (stackIds != null) { + for (int i = 0; i < stackIds.length; ++i) { + builder.addStackId(stackIds[i]); + } + } + + if (proc.hasException()) { + RemoteProcedureException exception = proc.getException(); + builder.setException( + RemoteProcedureException.toProto(exception.getSource(), exception.getCause())); + } + + final byte[] result = proc.getResult(); + if (result != null) { + builder.setResult(HBaseZeroCopyByteString.wrap(result)); + } + + final ByteString.Output stateStream = ByteString.newOutput(); + try { + proc.serializeStateData(stateStream); + if (stateStream.size() > 0) { + builder.setStateData(stateStream.toByteString()); + } + } finally { + stateStream.close(); + } + + if (proc.getNonceKey() != null) { + builder.setNonceGroup(proc.getNonceKey().getNonceGroup()); + builder.setNonce(proc.getNonceKey().getNonce()); + } + + return builder.build(); + } + + /** + * Helper to convert the protobuf procedure. + * Used by ProcedureStore implementations. + * + * TODO: OPTIMIZATION: some of the field never change during the execution + * (e.g. className, procId, parentId, ...). + * We can split in 'data' and 'state', and the store + * may take advantage of it by storing the data only on insert(). + */ + public static Procedure convertToProcedure(final ProcedureProtos.Procedure proto) throws IOException { + // Procedure from class name + final Procedure proc = newProcedure(proto.getClassName()); + + // set fields + proc.setProcId(proto.getProcId()); + proc.setState(proto.getState()); + proc.setStartTime(proto.getStartTime()); + proc.setLastUpdate(proto.getLastUpdate()); + + if (proto.hasParentId()) { + proc.setParentProcId(proto.getParentId()); + } + + if (proto.hasOwner()) { + proc.setOwner(proto.getOwner()); + } + + if (proto.hasTimeout()) { + proc.setTimeout(proto.getTimeout()); + } + + if (proto.getStackIdCount() > 0) { + proc.setStackIndexes(proto.getStackIdList()); + } + + if (proto.hasException()) { + assert proc.getState() == ProcedureProtos.ProcedureState.FINISHED || + proc.getState() == ProcedureProtos.ProcedureState.ROLLEDBACK : + "The procedure must be failed (waiting to rollback) or rolledback"; + proc.setFailure(RemoteProcedureException.fromProto(proto.getException())); + } + + if (proto.hasResult()) { + proc.setResult(proto.getResult().toByteArray()); + } + + if (proto.getNonce() != HConstants.NO_NONCE) { + proc.setNonceKey(new NonceKey(proto.getNonceGroup(), proto.getNonce())); + } + + // we want to call deserialize even when the stream is empty, mainly for testing. + proc.deserializeStateData(proto.getStateData().newInput()); + + return proc; + } + + // ========================================================================== + // convert to and from ProcedureInfo object + // ========================================================================== + + /** + * @return Convert the current {@link ProcedureInfo} into a Protocol Buffers Procedure + * instance. + */ + public static ProcedureProtos.Procedure convertToProtoProcedure(final ProcedureInfo procInfo) { + final ProcedureProtos.Procedure.Builder builder = ProcedureProtos.Procedure.newBuilder(); + + builder.setClassName(procInfo.getProcName()); + builder.setProcId(procInfo.getProcId()); + builder.setStartTime(procInfo.getStartTime()); + builder.setState(ProcedureProtos.ProcedureState.valueOf(procInfo.getProcState().name())); + builder.setLastUpdate(procInfo.getLastUpdate()); + + if (procInfo.hasParentId()) { + builder.setParentId(procInfo.getParentId()); + } + + if (procInfo.hasOwner()) { + builder.setOwner(procInfo.getProcOwner()); + } + + if (procInfo.isFailed()) { + builder.setException(ForeignExceptionUtil. + toProtoForeignException("", procInfo.getException())); + } + + if (procInfo.hasResultData()) { + builder.setResult(HBaseZeroCopyByteString.wrap(procInfo.getResult())); + } + + return builder.build(); + } + + public static ProcedureState convertToProcedureState(ProcedureProtos.ProcedureState state) { + return ProcedureState.valueOf(state.name()); + } + + public static ProcedureInfo convertToProcedureInfo(final Procedure proc) { + return convertToProcedureInfo(proc, null); + } + + public static ProcedureInfo convertToProcedureInfo(final Procedure proc, + final NonceKey nonceKey) { + return new ProcedureInfo(proc.getProcId(), + proc.toStringClass(), + proc.getOwner(), + proc.getState(), + proc.hasParent() ? proc.getParentProcId() : -1, + nonceKey, + proc.hasException()? + ForeignExceptionUtil.toProtoForeignException( + "ForeignException made when converting Procedure to ProcedureInfo", + proc.getException()): null, + proc.getLastUpdate(), proc.getStartTime(), proc.getResult()); + } +} \ No newline at end of file diff --git a/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/ProcedureTestingUtility.java b/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/ProcedureTestingUtility.java index 8b49e53..f5b0464 100644 --- a/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/ProcedureTestingUtility.java +++ b/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/ProcedureTestingUtility.java @@ -40,6 +40,7 @@ import org.apache.hadoop.hbase.procedure2.store.NoopProcedureStore; import org.apache.hadoop.hbase.procedure2.store.wal.WALProcedureStore; import org.apache.hadoop.hbase.protobuf.generated.ErrorHandlingProtos.ForeignExceptionMessage; import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState; +import org.apache.hadoop.hbase.util.NonceKey; import org.apache.hadoop.hbase.util.Threads; import static org.junit.Assert.assertEquals; @@ -158,13 +159,20 @@ public class ProcedureTestingUtility { } public static long submitAndWait(ProcedureExecutor procExecutor, Procedure proc, - final long nonceGroup, - final long nonce) { - long procId = procExecutor.submitProcedure(proc, nonceGroup, nonce); + final long nonceGroup, final long nonce) { + long procId = submitProcedure(procExecutor, proc, nonceGroup, nonce); waitProcedure(procExecutor, procId); return procId; } + public static long submitProcedure(ProcedureExecutor procExecutor, Procedure proc, + final long nonceGroup, final long nonce) { + final NonceKey nonceKey = procExecutor.createNonceKey(nonceGroup, nonce); + long procId = procExecutor.registerNonce(nonceKey); + assertFalse(procId >= 0); + return procExecutor.submitProcedure(proc, nonceKey); + } + public static void waitProcedure(ProcedureExecutor procExecutor, Procedure proc) { while (proc.getState() == ProcedureState.INITIALIZING) { Threads.sleepWithoutInterrupt(250); @@ -210,6 +218,12 @@ public class ProcedureTestingUtility { assertFalse(msg, result.isFailed()); } + public static Throwable assertProcFailed(final ProcedureInfo result) { + assertEquals(true, result.isFailed()); + LOG.info("procId=" + result.getProcId() + " exception: " + result.getException().getMessage()); + return getExceptionCause(result); + } + public static void assertIsAbortException(final ProcedureInfo result) { assertEquals(true, result.isFailed()); LOG.info(result.getExceptionFullMessage()); diff --git a/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureNonce.java b/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureNonce.java new file mode 100644 index 0000000..f275426 --- /dev/null +++ b/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureNonce.java @@ -0,0 +1,285 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.procedure2; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.CountDownLatch; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.HBaseCommonTestingUtility; +import org.apache.hadoop.hbase.ProcedureInfo; +import org.apache.hadoop.hbase.procedure2.store.ProcedureStore; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.testclassification.MasterTests; +import org.apache.hadoop.hbase.security.User; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.NonceKey; +import org.apache.hadoop.hbase.util.Threads; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +@Category({MasterTests.class, SmallTests.class}) +public class TestProcedureNonce { + private static final Log LOG = LogFactory.getLog(TestProcedureNonce.class); + + private static final int PROCEDURE_EXECUTOR_SLOTS = 2; + + private static TestProcEnv procEnv; + private static ProcedureExecutor procExecutor; + private static ProcedureStore procStore; + + private HBaseCommonTestingUtility htu; + private FileSystem fs; + private Path logDir; + + @Before + public void setUp() throws IOException { + htu = new HBaseCommonTestingUtility(); + Path testDir = htu.getDataTestDir(); + fs = testDir.getFileSystem(htu.getConfiguration()); + assertTrue(testDir.depth() > 1); + + logDir = new Path(testDir, "proc-logs"); + procEnv = new TestProcEnv(); + procStore = ProcedureTestingUtility.createStore(htu.getConfiguration(), fs, logDir); + procExecutor = new ProcedureExecutor(htu.getConfiguration(), procEnv, procStore); + procExecutor.testing = new ProcedureExecutor.Testing(); + procStore.start(PROCEDURE_EXECUTOR_SLOTS); + procExecutor.start(PROCEDURE_EXECUTOR_SLOTS, true); + } + + @After + public void tearDown() throws IOException { + procExecutor.stop(); + procStore.stop(false); + fs.delete(logDir, true); + } + + @Test(timeout=30000) + public void testCompletedProcWithSameNonce() throws Exception { + final long nonceGroup = 123; + final long nonce = 2222; + + // register the nonce + final NonceKey nonceKey = procExecutor.createNonceKey(nonceGroup, nonce); + assertFalse(procExecutor.registerNonce(nonceKey) >= 0); + + // Submit a proc and wait for its completion + Procedure proc = new TestSingleStepProcedure(); + long procId = procExecutor.submitProcedure(proc, nonceKey); + ProcedureTestingUtility.waitProcedure(procExecutor, procId); + + // Restart + ProcedureTestingUtility.restart(procExecutor); + ProcedureTestingUtility.waitProcedure(procExecutor, procId); + + // try to register a procedure with the same nonce + // we should get back the old procId + assertEquals(procId, procExecutor.registerNonce(nonceKey)); + + ProcedureInfo result = procExecutor.getResult(procId); + ProcedureTestingUtility.assertProcNotFailed(result); + } + + @Test(timeout=30000) + public void testRunningProcWithSameNonce() throws Exception { + final long nonceGroup = 456; + final long nonce = 33333; + + // register the nonce + final NonceKey nonceKey = procExecutor.createNonceKey(nonceGroup, nonce); + assertFalse(procExecutor.registerNonce(nonceKey) >= 0); + + // Submit a proc and use a latch to prevent the step execution until we submitted proc2 + CountDownLatch latch = new CountDownLatch(1); + TestSingleStepProcedure proc = new TestSingleStepProcedure(); + procEnv.setWaitLatch(latch); + long procId = procExecutor.submitProcedure(proc, nonceKey); + while (proc.step != 1) Threads.sleep(25); + + // try to register a procedure with the same nonce + // we should get back the old procId + assertEquals(procId, procExecutor.registerNonce(nonceKey)); + + // complete the procedure + latch.countDown(); + + // Restart, the procedure is not completed yet + ProcedureTestingUtility.restart(procExecutor); + ProcedureTestingUtility.waitProcedure(procExecutor, procId); + + // try to register a procedure with the same nonce + // we should get back the old procId + assertEquals(procId, procExecutor.registerNonce(nonceKey)); + + ProcedureInfo result = procExecutor.getResult(procId); + ProcedureTestingUtility.assertProcNotFailed(result); + } + + @Test + public void testSetFailureResultForNonce() throws IOException { + final long nonceGroup = 234; + final long nonce = 55555; + + // check and register the request nonce + final NonceKey nonceKey = procExecutor.createNonceKey(nonceGroup, nonce); + assertFalse(procExecutor.registerNonce(nonceKey) >= 0); + + procExecutor.setFailureResultForNonce(nonceKey, "testProc", User.getCurrent(), + new IOException("test failure")); + + final long procId = procExecutor.registerNonce(nonceKey); + ProcedureInfo result = procExecutor.getResult(procId); + ProcedureTestingUtility.assertProcFailed(result); + } + + @Test(timeout=30000) + public void testConcurrentNonceRegistration() throws IOException { + testConcurrentNonceRegistration(true, 567, 44444); + } + + @Test(timeout=30000) + public void testConcurrentNonceRegistrationWithRollback() throws IOException { + testConcurrentNonceRegistration(false, 890, 55555); + } + + private void testConcurrentNonceRegistration(final boolean submitProcedure, + final long nonceGroup, final long nonce) throws IOException { + // register the nonce + final NonceKey nonceKey = procExecutor.createNonceKey(nonceGroup, nonce); + + final AtomicReference t1Exception = new AtomicReference(); + final AtomicReference t2Exception = new AtomicReference(); + + final CountDownLatch t1NonceRegisteredLatch = new CountDownLatch(1); + final CountDownLatch t2BeforeNonceRegisteredLatch = new CountDownLatch(1); + final Thread[] threads = new Thread[2]; + threads[0] = new Thread() { + @Override + public void run() { + try { + // release the nonce and wake t2 + assertFalse("unexpected already registered nonce", + procExecutor.registerNonce(nonceKey) >= 0); + t1NonceRegisteredLatch.countDown(); + + // hold the submission until t2 is registering the nonce + t2BeforeNonceRegisteredLatch.await(); + Threads.sleep(1000); + + if (submitProcedure) { + CountDownLatch latch = new CountDownLatch(1); + TestSingleStepProcedure proc = new TestSingleStepProcedure(); + procEnv.setWaitLatch(latch); + + procExecutor.submitProcedure(proc, nonceKey); + Threads.sleep(100); + + // complete the procedure + latch.countDown(); + } else { + procExecutor.unregisterNonceIfProcedureWasNotSubmitted(nonceKey); + } + } catch (Throwable e) { + t1Exception.set(e); + } finally { + t1NonceRegisteredLatch.countDown(); + t2BeforeNonceRegisteredLatch.countDown(); + } + } + }; + + threads[1] = new Thread() { + @Override + public void run() { + try { + // wait until t1 has registered the nonce + t1NonceRegisteredLatch.await(); + + // register the nonce + t2BeforeNonceRegisteredLatch.countDown(); + assertFalse("unexpected non registered nonce", + procExecutor.registerNonce(nonceKey) < 0); + } catch (Throwable e) { + t2Exception.set(e); + } finally { + t1NonceRegisteredLatch.countDown(); + t2BeforeNonceRegisteredLatch.countDown(); + } + } + }; + + for (int i = 0; i < threads.length; ++i) threads[i].start(); + for (int i = 0; i < threads.length; ++i) Threads.shutdown(threads[i]); + ProcedureTestingUtility.waitNoProcedureRunning(procExecutor); + assertEquals(null, t1Exception.get()); + assertEquals(null, t2Exception.get()); + } + + public static class TestSingleStepProcedure extends SequentialProcedure { + private int step = 0; + + public TestSingleStepProcedure() { } + + @Override + protected Procedure[] execute(TestProcEnv env) throws InterruptedException { + step++; + env.waitOnLatch(); + LOG.debug("execute procedure " + this + " step=" + step); + step++; + setResult(Bytes.toBytes(step)); + return null; + } + + @Override + protected void rollback(TestProcEnv env) { } + + @Override + protected boolean abort(TestProcEnv env) { return true; } + } + + private static class TestProcEnv { + private CountDownLatch latch = null; + + /** + * set/unset a latch. every procedure execute() step will wait on the latch if any. + */ + public void setWaitLatch(CountDownLatch latch) { + this.latch = latch; + } + + public void waitOnLatch() throws InterruptedException { + if (latch != null) { + latch.await(); + } + } + } +} \ No newline at end of file diff --git a/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureRecovery.java b/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureRecovery.java index 98aedce..fa9ddfa 100644 --- a/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureRecovery.java +++ b/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureRecovery.java @@ -287,49 +287,6 @@ public class TestProcedureRecovery { ProcedureTestingUtility.assertIsAbortException(result); } - @Test(timeout=30000) - public void testCompletedProcWithSameNonce() throws Exception { - final long nonceGroup = 123; - final long nonce = 2222; - Procedure proc = new TestSingleStepProcedure(); - // Submit a proc and wait for its completion - long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc, nonceGroup, nonce); - - // Restart - restart(); - waitProcedure(procId); - - Procedure proc2 = new TestSingleStepProcedure(); - // Submit a procedure with the same nonce and expect the same procedure would return. - long procId2 = ProcedureTestingUtility.submitAndWait(procExecutor, proc2, nonceGroup, nonce); - assertTrue(procId == procId2); - - ProcedureInfo result = procExecutor.getResult(procId2); - ProcedureTestingUtility.assertProcNotFailed(result); - } - - @Test(timeout=30000) - public void testRunningProcWithSameNonce() throws Exception { - final long nonceGroup = 456; - final long nonce = 33333; - Procedure proc = new TestSingleStepProcedure(); - long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc, nonceGroup, nonce); - - // Restart (use a latch to prevent the step execution until we submitted proc2) - CountDownLatch latch = new CountDownLatch(1); - procEnv.setWaitLatch(latch); - restart(); - // Submit a procedure with the same nonce and expect the same procedure would return. - Procedure proc2 = new TestSingleStepProcedure(); - long procId2 = procExecutor.submitProcedure(proc2, nonceGroup, nonce); - latch.countDown(); - procEnv.setWaitLatch(null); - - // The original proc is not completed and the new submission should have the same proc Id. - assertTrue(procId == procId2); - } - - public static class TestStateMachineProcedure extends StateMachineProcedure { enum State { STATE_1, STATE_2, STATE_3, DONE } 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 b68ca55..122ca19 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 @@ -83,6 +83,7 @@ import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitorBase; import org.apache.hadoop.hbase.client.RegionReplicaUtil; import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.coprocessor.BypassCoprocessorException; import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.executor.ExecutorType; @@ -117,6 +118,7 @@ import org.apache.hadoop.hbase.master.procedure.MasterProcedureConstants; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; import org.apache.hadoop.hbase.master.procedure.MasterProcedureScheduler.ProcedureEvent; import org.apache.hadoop.hbase.master.procedure.ModifyColumnFamilyProcedure; +import org.apache.hadoop.hbase.master.procedure.MasterProcedureUtil; import org.apache.hadoop.hbase.master.procedure.ModifyNamespaceProcedure; import org.apache.hadoop.hbase.master.procedure.ModifyTableProcedure; import org.apache.hadoop.hbase.master.procedure.ProcedurePrepareLatch; @@ -133,6 +135,7 @@ import org.apache.hadoop.hbase.procedure.flush.MasterFlushTableProcedureManager; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.procedure2.store.wal.WALProcedureStore; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionServerInfo; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription; import org.apache.hadoop.hbase.protobuf.generated.WALProtos; import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos; import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode; @@ -158,6 +161,7 @@ import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.util.HFileArchiveUtil; import org.apache.hadoop.hbase.util.HasThread; import org.apache.hadoop.hbase.util.ModifyRegionUtils; +import org.apache.hadoop.hbase.util.NonceKey; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.Threads; import org.apache.hadoop.hbase.util.VersionInfo; @@ -1653,37 +1657,33 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final byte [][] splitKeys, final long nonceGroup, final long nonce) throws IOException { - if (isStopped()) { - throw new MasterNotRunningException(); - } - + checkInitialized(); String namespace = hTableDescriptor.getTableName().getNamespaceAsString(); ensureNamespaceExists(namespace); - - HRegionInfo[] newRegions = ModifyRegionUtils.createHRegionInfos(hTableDescriptor, splitKeys); - checkInitialized(); + final HRegionInfo[] newRegions = + ModifyRegionUtils.createHRegionInfos(hTableDescriptor, splitKeys); sanityCheckTableDescriptor(hTableDescriptor); + return MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + getMaster().getMasterCoprocessorHost().preCreateTable(hTableDescriptor, newRegions); + LOG.info(getClientIdAuditPrefix() + " create " + hTableDescriptor); + // TODO: We can handle/merge duplicate requests, and differentiate the case of + // TableExistsException by saying if the schema is the same or not. + ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new CreateTableProcedure( + procedureExecutor.getEnvironment(), hTableDescriptor, newRegions, latch)); + latch.await(); + + getMaster().getMasterCoprocessorHost().postCreateTable(hTableDescriptor, newRegions); + } - if (cpHost != null) { - cpHost.preCreateTable(hTableDescriptor, newRegions); - } - LOG.info(getClientIdAuditPrefix() + " create " + hTableDescriptor); - - // TODO: We can handle/merge duplicate requests, and differentiate the case of - // TableExistsException by saying if the schema is the same or not. - ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); - long procId = this.procedureExecutor.submitProcedure( - new CreateTableProcedure( - procedureExecutor.getEnvironment(), hTableDescriptor, newRegions, latch), - nonceGroup, - nonce); - latch.await(); - - if (cpHost != null) { - cpHost.postCreateTable(hTableDescriptor, newRegions); - } - - return procId; + @Override + protected String getDescription() { + return "CreateTableProcedure"; + } + }); } @Override @@ -2022,24 +2022,29 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final long nonceGroup, final long nonce) throws IOException { checkInitialized(); - if (cpHost != null) { - cpHost.preDeleteTable(tableName); - } - LOG.info(getClientIdAuditPrefix() + " delete " + tableName); - // TODO: We can handle/merge duplicate request - ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); - long procId = this.procedureExecutor.submitProcedure( - new DeleteTableProcedure(procedureExecutor.getEnvironment(), tableName, latch), - nonceGroup, - nonce); - latch.await(); + return MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + getMaster().getMasterCoprocessorHost().preDeleteTable(tableName); - if (cpHost != null) { - cpHost.postDeleteTable(tableName); - } + LOG.info(getClientIdAuditPrefix() + " delete " + tableName); - return procId; + // TODO: We can handle/merge duplicate request + ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new DeleteTableProcedure(procedureExecutor.getEnvironment(), + tableName, latch)); + latch.await(); + + getMaster().getMasterCoprocessorHost().postDeleteTable(tableName); + } + + @Override + protected String getDescription() { + return "DeleteTableProcedure"; + } + }); } @Override @@ -2049,20 +2054,25 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final long nonceGroup, final long nonce) throws IOException { checkInitialized(); - if (cpHost != null) { - cpHost.preTruncateTable(tableName); - } - LOG.info(getClientIdAuditPrefix() + " truncate " + tableName); - - long procId = this.procedureExecutor.submitProcedure( - new TruncateTableProcedure(procedureExecutor.getEnvironment(), tableName, preserveSplits), - nonceGroup, - nonce); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + getMaster().getMasterCoprocessorHost().preTruncateTable(tableName); + LOG.info(getClientIdAuditPrefix() + " truncate " + tableName); + ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new TruncateTableProcedure(procedureExecutor.getEnvironment(), + tableName, preserveSplits, latch)); + latch.await(); + + getMaster().getMasterCoprocessorHost().postTruncateTable(tableName); + } - if (cpHost != null) { - cpHost.postTruncateTable(tableName); - } + @Override + protected String getDescription() { + return "TruncateTableProcedure"; + } + }); } @Override @@ -2076,20 +2086,27 @@ public class HMaster extends HRegionServer implements MasterServices, Server { checkCompression(columnDescriptor); checkEncryption(conf, columnDescriptor); checkReplicationScope(columnDescriptor); - if (cpHost != null) { - if (cpHost.preAddColumn(tableName, columnDescriptor)) { - return; + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + if (getMaster().getMasterCoprocessorHost().preAddColumn(tableName, columnDescriptor)) { + return; + } + + // Execute the operation synchronously, wait for the operation to complete before continuing + ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new AddColumnFamilyProcedure(procedureExecutor.getEnvironment(), + tableName, columnDescriptor, latch)); + latch.await(); + + getMaster().getMasterCoprocessorHost().postAddColumn(tableName, columnDescriptor); } - } - // Execute the operation synchronously - wait for the operation to complete before continuing. - long procId = this.procedureExecutor.submitProcedure( - new AddColumnFamilyProcedure(procedureExecutor.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); - if (cpHost != null) { - cpHost.postAddColumn(tableName, columnDescriptor); - } + @Override + protected String getDescription() { + return "AddColumnFamilyProcedure"; + } + }); } @Override @@ -2103,23 +2120,29 @@ public class HMaster extends HRegionServer implements MasterServices, Server { checkCompression(descriptor); checkEncryption(conf, descriptor); checkReplicationScope(descriptor); - if (cpHost != null) { - if (cpHost.preModifyColumn(tableName, descriptor)) { - return; - } - } - LOG.info(getClientIdAuditPrefix() + " modify " + descriptor); + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + if (getMaster().getMasterCoprocessorHost().preModifyColumn(tableName, descriptor)) { + return; + } + LOG.info(getClientIdAuditPrefix() + " modify " + descriptor); - // Execute the operation synchronously - wait for the operation to complete before continuing. - long procId = this.procedureExecutor.submitProcedure( - new ModifyColumnFamilyProcedure(procedureExecutor.getEnvironment(), tableName, descriptor), - nonceGroup, - nonce); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); + // Execute the operation synchronously - wait for the operation to complete before continuing. + ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new ModifyColumnFamilyProcedure(procedureExecutor.getEnvironment(), + tableName, descriptor, latch)); + latch.await(); - if (cpHost != null) { - cpHost.postModifyColumn(tableName, descriptor); - } + getMaster().getMasterCoprocessorHost().postModifyColumn(tableName, descriptor); + } + + @Override + protected String getDescription() { + return "ModifyColumnFamilyProcedure"; + } + }); } @Override @@ -2130,23 +2153,29 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final long nonce) throws IOException { checkInitialized(); - if (cpHost != null) { - if (cpHost.preDeleteColumn(tableName, columnName)) { - return; - } - } - LOG.info(getClientIdAuditPrefix() + " delete " + Bytes.toString(columnName)); + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + if (getMaster().getMasterCoprocessorHost().preDeleteColumn(tableName, columnName)) { + return; + } + LOG.info(getClientIdAuditPrefix() + " delete " + Bytes.toString(columnName)); - // Execute the operation synchronously - wait for the operation to complete before continuing. - long procId = this.procedureExecutor.submitProcedure( - new DeleteColumnFamilyProcedure(procedureExecutor.getEnvironment(), tableName, columnName), - nonceGroup, - nonce); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); + // Execute the operation synchronously - wait for the operation to complete before continuing. + ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new DeleteColumnFamilyProcedure(procedureExecutor.getEnvironment(), + tableName, columnName, latch)); + latch.await(); - if (cpHost != null) { - cpHost.postDeleteColumn(tableName, columnName); - } + getMaster().getMasterCoprocessorHost().postDeleteColumn(tableName, columnName); + } + + @Override + protected String getDescription() { + return "DeleteColumnFamilyProcedure"; + } + }); } @Override @@ -2155,28 +2184,31 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final long nonceGroup, final long nonce) throws IOException { checkInitialized(); - if (cpHost != null) { - cpHost.preEnableTable(tableName); - } - LOG.info(getClientIdAuditPrefix() + " enable " + tableName); - - // Execute the operation asynchronously - client will check the progress of the operation - final ProcedurePrepareLatch prepareLatch = ProcedurePrepareLatch.createLatch(); - long procId = this.procedureExecutor.submitProcedure( - new EnableTableProcedure(procedureExecutor.getEnvironment(), tableName, false, prepareLatch), - nonceGroup, - nonce); - // Before returning to client, we want to make sure that the table is prepared to be - // enabled (the table is locked and the table state is set). - // - // Note: if the procedure throws exception, we will catch it and rethrow. - prepareLatch.await(); - - if (cpHost != null) { - cpHost.postEnableTable(tableName); - } - - return procId; + return MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + getMaster().getMasterCoprocessorHost().preEnableTable(tableName); + + LOG.info(getClientIdAuditPrefix() + " enable " + tableName); + + // Execute the operation asynchronously - client will check the progress of the operation + // In case the request is from a <1.1 client before returning, + // we want to make sure that the table is prepared to be + // enabled (the table is locked and the table state is set). + // Note: if the procedure throws exception, we will catch it and rethrow. + final ProcedurePrepareLatch prepareLatch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new EnableTableProcedure(procedureExecutor.getEnvironment(), + tableName, false, prepareLatch)); + prepareLatch.await(); + + getMaster().getMasterCoprocessorHost().postEnableTable(tableName); + } + @Override + protected String getDescription() { + return "EnableTableProcedure"; + } + }); } @Override @@ -2185,29 +2217,31 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final long nonceGroup, final long nonce) throws IOException { checkInitialized(); - if (cpHost != null) { - cpHost.preDisableTable(tableName); - } - LOG.info(getClientIdAuditPrefix() + " disable " + tableName); - - // Execute the operation asynchronously - client will check the progress of the operation - final ProcedurePrepareLatch prepareLatch = ProcedurePrepareLatch.createLatch(); - // Execute the operation asynchronously - client will check the progress of the operation - long procId = this.procedureExecutor.submitProcedure( - new DisableTableProcedure(procedureExecutor.getEnvironment(), tableName, false, prepareLatch), - nonceGroup, - nonce); - // Before returning to client, we want to make sure that the table is prepared to be - // enabled (the table is locked and the table state is set). - // - // Note: if the procedure throws exception, we will catch it and rethrow. - prepareLatch.await(); - - if (cpHost != null) { - cpHost.postDisableTable(tableName); - } - - return procId; + return MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + getMaster().getMasterCoprocessorHost().preDisableTable(tableName); + + LOG.info(getClientIdAuditPrefix() + " disable " + tableName); + + // Execute the operation asynchronously - client will check the progress of the operation + // In case the request is from a <1.1 client before returning, + // we want to make sure that the table is prepared to be + // enabled (the table is locked and the table state is set). + // Note: if the procedure throws exception, we will catch it and rethrow. + final ProcedurePrepareLatch prepareLatch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new DisableTableProcedure(procedureExecutor.getEnvironment(), + tableName, false, prepareLatch)); + prepareLatch.await(); + + getMaster().getMasterCoprocessorHost().postDisableTable(tableName); + } + @Override + protected String getDescription() { + return "DisableTableProcedure"; + } + }); } /** @@ -2255,23 +2289,48 @@ public class HMaster extends HRegionServer implements MasterServices, Server { throws IOException { checkInitialized(); sanityCheckTableDescriptor(descriptor); - if (cpHost != null) { - cpHost.preModifyTable(tableName, descriptor); - } + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + getMaster().getMasterCoprocessorHost().preModifyTable(tableName, descriptor); + LOG.info(getClientIdAuditPrefix() + " modify " + tableName); + // Execute the operation synchronously - wait for the operation completes before continuing. + ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(); + submitProcedure(new ModifyTableProcedure(procedureExecutor.getEnvironment(), + descriptor, latch)); + latch.await(); + getMaster().getMasterCoprocessorHost().postModifyTable(tableName, descriptor); + } - LOG.info(getClientIdAuditPrefix() + " modify " + tableName); + @Override + protected String getDescription() { + return "ModifyTableProcedure"; + } + }); + } - // Execute the operation synchronously - wait for the operation completes before continuing. - long procId = this.procedureExecutor.submitProcedure( - new ModifyTableProcedure(procedureExecutor.getEnvironment(), descriptor), - nonceGroup, - nonce); + public long restoreSnapshot(final SnapshotDescription snapshotDesc, + final long nonceGroup, final long nonce) throws IOException { + checkInitialized(); + getSnapshotManager().checkSnapshotSupport(); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); + // Ensure namespace exists. Will throw exception if non-known NS. + final TableName dstTable = TableName.valueOf(snapshotDesc.getTable()); + getNamespace(dstTable.getNamespaceAsString()); - if (cpHost != null) { - cpHost.postModifyTable(tableName, descriptor); - } + return MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + setProcId(getSnapshotManager().restoreOrCloneSnapshot(snapshotDesc, getNonceKey())); + } + + @Override + protected String getDescription() { + return "RestoreSnapshotProcedure"; + } + }); } @Override @@ -2496,6 +2555,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server { if (!isInitialized()) { throw new PleaseHoldException("Master is initializing"); } + if (isStopped()) throw new MasterNotRunningException(); } void checkNamespaceManagerReady() throws IOException { @@ -2684,6 +2744,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final NamespaceDescriptor descriptor, final long nonceGroup, final long nonce) throws IOException { + checkInitialized(); TableName.isLegalNamespaceName(Bytes.toBytes(descriptor.getName())); checkNamespaceManagerReady(); if (cpHost != null) { @@ -2699,40 +2760,58 @@ public class HMaster extends HRegionServer implements MasterServices, Server { @Override public void createNamespaceSync( - final NamespaceDescriptor descriptor, + final NamespaceDescriptor namespaceDescriptor, final long nonceGroup, final long nonce) throws IOException { - LOG.info(getClientIdAuditPrefix() + " creating " + descriptor); - // Execute the operation synchronously - wait for the operation to complete before continuing. - long procId = this.procedureExecutor.submitProcedure( - new CreateNamespaceProcedure(procedureExecutor.getEnvironment(), descriptor), - nonceGroup, - nonce); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); + checkInitialized(); + TableName.isLegalNamespaceName(Bytes.toBytes(namespaceDescriptor.getName())); + checkNamespaceManagerReady(); + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + if (getMaster().getMasterCoprocessorHost().preCreateNamespace(namespaceDescriptor)) { + throw new BypassCoprocessorException(); + } + LOG.info(getClientIdAuditPrefix() + " creating " + namespaceDescriptor); + // Execute the operation synchronously - wait for the operation to complete before continuing. + setProcId(createNamespace(namespaceDescriptor, getNonceKey())); + getMaster().getMasterCoprocessorHost().postCreateNamespace(namespaceDescriptor); + } + + @Override + protected String getDescription() { + return "CreateTableProcedure"; + } + }); } @Override public void modifyNamespace( - final NamespaceDescriptor descriptor, + final NamespaceDescriptor namespaceDescriptor, final long nonceGroup, final long nonce) throws IOException { + checkInitialized(); TableName.isLegalNamespaceName(Bytes.toBytes(descriptor.getName())); checkNamespaceManagerReady(); - if (cpHost != null) { - if (cpHost.preModifyNamespace(descriptor)) { - return; + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + if (getMaster().getMasterCoprocessorHost().preModifyNamespace(namespaceDescriptor)) { + throw new BypassCoprocessorException(); + } + LOG.info(getClientIdAuditPrefix() + " modify " + namespaceDescriptor); + // Execute the operation synchronously - wait for the operation to complete before continuing. + setProcId(modifyNamespace(namespaceDescriptor, getNonceKey())); + getMaster().getMasterCoprocessorHost().postModifyNamespace(namespaceDescriptor); } - } - LOG.info(getClientIdAuditPrefix() + " modify " + descriptor); - // Execute the operation synchronously - wait for the operation to complete before continuing. - long procId = this.procedureExecutor.submitProcedure( - new ModifyNamespaceProcedure(procedureExecutor.getEnvironment(), descriptor), - nonceGroup, - nonce); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); - if (cpHost != null) { - cpHost.postModifyNamespace(descriptor); - } + + @Override + protected String getDescription() { + return "CreateTableProcedure"; + } + }); } @Override @@ -2740,22 +2819,26 @@ public class HMaster extends HRegionServer implements MasterServices, Server { final String name, final long nonceGroup, final long nonce) throws IOException { + checkInitialized(); checkNamespaceManagerReady(); - if (cpHost != null) { - if (cpHost.preDeleteNamespace(name)) { - return; + MasterProcedureUtil.submitProcedure( + new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { + @Override + protected void run() throws IOException { + if (getMaster().getMasterCoprocessorHost().preDeleteNamespace(name)) { + throw new BypassCoprocessorException(); + } + LOG.info(getClientIdAuditPrefix() + " delete " + name); + // Execute the operation synchronously - wait for the operation to complete before continuing. + setProcId(deleteNamespace(name, getNonceKey())); + getMaster().getMasterCoprocessorHost().postDeleteNamespace(name); } - } - LOG.info(getClientIdAuditPrefix() + " delete " + name); - // Execute the operation synchronously - wait for the operation to complete before continuing. - long procId = this.procedureExecutor.submitProcedure( - new DeleteNamespaceProcedure(procedureExecutor.getEnvironment(), name), - nonceGroup, - nonce); - ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId); - if (cpHost != null) { - cpHost.postDeleteNamespace(name); - } + + @Override + protected String getDescription() { + return "DeleteNamespaceProcedure"; + } + }); } /** diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java index f51a797..5ac1f6c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java @@ -1275,15 +1275,8 @@ public class MasterRpcServices extends RSRpcServices public RestoreSnapshotResponse restoreSnapshot(RpcController controller, RestoreSnapshotRequest request) throws ServiceException { try { - master.checkInitialized(); - master.snapshotManager.checkSnapshotSupport(); - - // ensure namespace exists - TableName dstTable = TableName.valueOf(request.getSnapshot().getTable()); - master.ensureNamespaceExists(dstTable.getNamespaceAsString()); - - SnapshotDescription reqSnapshot = request.getSnapshot(); - master.snapshotManager.restoreSnapshot(reqSnapshot); + long procId = master.restoreSnapshot(request.getSnapshot(), + request.getNonceGroup(), request.getNonce()); return RestoreSnapshotResponse.newBuilder().build(); } catch (ForeignException e) { throw new ServiceException(e.getCause()); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java index d7c0b92..f66ef45 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java @@ -18,12 +18,18 @@ package org.apache.hadoop.hbase.master.procedure; +import java.io.IOException; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceStability; +import org.apache.hadoop.hbase.master.MasterServices; +import org.apache.hadoop.hbase.procedure2.Procedure; +import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.protobuf.generated.RPCProtos.UserInformation; import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.hbase.util.NonceKey; @InterfaceAudience.Private @InterfaceStability.Evolving @@ -53,4 +59,85 @@ public final class MasterProcedureUtil { } return null; } + + /** + * Helper Runnable used in conjunction with submitProcedure() to deal with + * submitting procs with nonce. + * See submitProcedure() for an example. + */ + public static abstract class NonceProcedureRunnable { + private final MasterServices master; + private final NonceKey nonceKey; + private Long procId; + + public NonceProcedureRunnable(final MasterServices master, + final long nonceGroup, final long nonce) { + this.master = master; + this.nonceKey = getProcedureExecutor().createNonceKey(nonceGroup, nonce); + } + + protected NonceKey getNonceKey() { + return nonceKey; + } + + protected MasterServices getMaster() { + return master; + } + + protected ProcedureExecutor getProcedureExecutor() { + return master.getMasterProcedureExecutor(); + } + + protected long getProcId() { + return procId != null ? procId.longValue() : -1; + } + + protected long setProcId(final long procId) { + this.procId = procId; + return procId; + } + + protected abstract void run() throws IOException; + protected abstract String getDescription(); + + protected long submitProcedure(final Procedure proc) { + assert procId == null : "submitProcedure() was already called, running procId=" + procId; + procId = getProcedureExecutor().submitProcedure(proc, nonceKey); + return procId; + } + } + + /** + * Helper used to deal with submitting procs with nonce. + * Internally the NonceProcedureRunnable.run() will be called only if no one else + * registered the nonce. any Exception thrown by the run() method will be + * collected/handled and rethrown. + * + * long procId = MasterProcedureUtil.submitProcedure( + * new NonceProcedureRunnable(procExec, nonceGroup, nonce) { + * {@literal @}Override + * public void run() { + * cpHost.preOperation(); + * submitProcedure(new MyProc()); + * cpHost.postOperation(); + * } + * }); + * + */ + public static long submitProcedure(final NonceProcedureRunnable runnable) throws IOException { + final ProcedureExecutor procExec = runnable.getProcedureExecutor(); + final long procId = procExec.registerNonce(runnable.getNonceKey()); + if (procId >= 0) return procId; // someone already registered the nonce + try { + runnable.run(); + } catch (IOException e) { + procExec.setFailureResultForNonce(runnable.getNonceKey(), + runnable.getDescription(), + procExec.getEnvironment().getRequestUser(), e); + throw e; + } finally { + procExec.unregisterNonceIfProcedureWasNotSubmitted(runnable.getNonceKey()); + } + return runnable.getProcId(); + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestAddColumnFamilyProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestAddColumnFamilyProcedure.java index 97a287e..6ebdf05 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestAddColumnFamilyProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestAddColumnFamilyProcedure.java @@ -99,9 +99,7 @@ public class TestAddColumnFamilyProcedure { // Test 1: Add a column family online long procId1 = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor1), - nonceGroup, - nonce); + new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor1)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); @@ -112,9 +110,7 @@ public class TestAddColumnFamilyProcedure { // Test 2: Add a column family offline UTIL.getHBaseAdmin().disableTable(tableName); long procId2 = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor2), - nonceGroup + 1, - nonce + 1); + new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor2)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); @@ -134,9 +130,7 @@ public class TestAddColumnFamilyProcedure { // add the column family long procId1 = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); + new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); @@ -145,9 +139,7 @@ public class TestAddColumnFamilyProcedure { // add the column family that exists long procId2 = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup + 1, - nonce + 1); + new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); @@ -161,9 +153,7 @@ public class TestAddColumnFamilyProcedure { // Do the same add the existing column family - this time offline UTIL.getHBaseAdmin().disableTable(tableName); long procId3 = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup + 2, - nonce + 2); + new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId3); @@ -175,37 +165,6 @@ public class TestAddColumnFamilyProcedure { ProcedureTestingUtility.getExceptionCause(result) instanceof InvalidFamilyOperationException); } - @Test(timeout=60000) - public void testAddSameColumnFamilyTwiceWithSameNonce() throws Exception { - final TableName tableName = TableName.valueOf("testAddSameColumnFamilyTwiceWithSameNonce"); - final String cf2 = "cf2"; - final HColumnDescriptor columnDescriptor = new HColumnDescriptor(cf2); - - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - - MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1"); - - // add the column family - long procId1 = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); - long procId2 = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); - // Wait the completion - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); - MasterProcedureTestingUtility.validateColumnFamilyAddition(UTIL.getHBaseCluster().getMaster(), - tableName, cf2); - - // Wait the completion and expect not fail - because it is the same proc - ProcedureTestingUtility.waitProcedure(procExec, procId2); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); - assertTrue(procId1 == procId2); - } - @Test(timeout = 60000) public void testRecoveryAndDoubleExecutionOffline() throws Exception { final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecutionOffline"); @@ -221,9 +180,7 @@ public class TestAddColumnFamilyProcedure { // Start the AddColumnFamily procedure && kill the executor long procId = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); + new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Restart the executor and execute the step twice int numberOfSteps = AddColumnFamilyState.values().length; @@ -248,9 +205,7 @@ public class TestAddColumnFamilyProcedure { // Start the AddColumnFamily procedure && kill the executor long procId = procExec.submitProcedure( - new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); + new AddColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Restart the executor and execute the step twice int numberOfSteps = AddColumnFamilyState.values().length; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java index e0027ee..7310706 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java @@ -51,9 +51,6 @@ public class TestCreateNamespaceProcedure { protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); - private static long nonceGroup = HConstants.NO_NONCE; - private static long nonce = HConstants.NO_NONCE; - private static void setupConf(Configuration conf) { conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); } @@ -76,9 +73,6 @@ public class TestCreateNamespaceProcedure { @Before public void setup() throws Exception { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false); - nonceGroup = - MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster()); - nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster()); } @After @@ -92,9 +86,7 @@ public class TestCreateNamespaceProcedure { final ProcedureExecutor procExec = getMasterProcedureExecutor(); long procId = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureTestingUtility.assertProcNotFailed(procExec, procId); @@ -109,18 +101,14 @@ public class TestCreateNamespaceProcedure { final ProcedureExecutor procExec = getMasterProcedureExecutor(); long procId1 = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); // Create the namespace that exists long procId2 = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup + 1, - nonce + 1); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); @@ -139,9 +127,7 @@ public class TestCreateNamespaceProcedure { final ProcedureExecutor procExec = getMasterProcedureExecutor(); long procId = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureInfo result = procExec.getResult(procId); @@ -162,9 +148,7 @@ public class TestCreateNamespaceProcedure { nsd.setConfiguration(nsKey, nsValue); long procId = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureInfo result = procExec.getResult(procId); @@ -184,9 +168,7 @@ public class TestCreateNamespaceProcedure { nsd.setConfiguration(nsKey, nsValue); long procId = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureInfo result = procExec.getResult(procId); @@ -195,32 +177,6 @@ public class TestCreateNamespaceProcedure { assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException); } - @Test(timeout=60000) - public void testCreateSameNamespaceTwiceWithSameNonce() throws Exception { - final NamespaceDescriptor nsd = - NamespaceDescriptor.create("testCreateSameNamespaceTwiceWithSameNonce").build(); - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - - long procId1 = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); - long procId2 = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); - // Wait the completion - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); - - validateNamespaceCreated(nsd); - - // Wait the completion and expect not fail - because it is the same proc - ProcedureTestingUtility.waitProcedure(procExec, procId2); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); - assertTrue(procId1 == procId2); - } - @Test(timeout = 60000) public void testRecoveryAndDoubleExecution() throws Exception { final NamespaceDescriptor nsd = @@ -232,9 +188,7 @@ public class TestCreateNamespaceProcedure { // Start the CreateNamespace procedure && kill the executor long procId = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Restart the executor and execute the step twice int numberOfSteps = CreateNamespaceState.values().length; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java index 2841847..06a675a 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java @@ -151,14 +151,12 @@ public class TestCreateTableProcedure { // create the table long procId1 = procExec.submitProcedure( - new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce); + new CreateTableProcedure(procExec.getEnvironment(), htd, regions)); // create another with the same name ProcedurePrepareLatch latch2 = new ProcedurePrepareLatch.CompatibilityLatch(); long procId2 = procExec.submitProcedure( - new CreateTableProcedure(procExec.getEnvironment(), htd, regions, latch2), - nonceGroup + 1, - nonce + 1); + new CreateTableProcedure(procExec.getEnvironment(), htd, regions, latch2)); ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId1)); @@ -168,29 +166,6 @@ public class TestCreateTableProcedure { } @Test(timeout=60000) - public void testCreateTwiceWithSameNonce() throws Exception { - final TableName tableName = TableName.valueOf("testCreateTwiceWithSameNonce"); - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - final HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f"); - final HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, null); - - // create the table - long procId1 = procExec.submitProcedure( - new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce); - - // create another with the same name - long procId2 = procExec.submitProcedure( - new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce); - - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId1)); - - ProcedureTestingUtility.waitProcedure(procExec, procId2); - ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId2)); - assertTrue(procId1 == procId2); - } - - @Test(timeout=60000) public void testRecoveryAndDoubleExecution() throws Exception { final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution"); @@ -203,7 +178,7 @@ public class TestCreateTableProcedure { HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2"); HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, splitKeys); long procId = procExec.submitProcedure( - new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce); + new CreateTableProcedure(procExec.getEnvironment(), htd, regions)); // Restart the executor and execute the step twice // NOTE: the 6 (number of CreateTableState steps) is hardcoded, diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteColumnFamilyProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteColumnFamilyProcedure.java index d5e79cf..d31fbe1 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteColumnFamilyProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteColumnFamilyProcedure.java @@ -97,9 +97,7 @@ public class TestDeleteColumnFamilyProcedure { // Test 1: delete the column family that exists online long procId1 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf1.getBytes()), - nonceGroup, - nonce); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf1.getBytes())); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); @@ -110,9 +108,7 @@ public class TestDeleteColumnFamilyProcedure { // Test 2: delete the column family that exists offline UTIL.getHBaseAdmin().disableTable(tableName); long procId2 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes()), - nonceGroup, - nonce); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes())); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); @@ -129,9 +125,7 @@ public class TestDeleteColumnFamilyProcedure { // delete the column family that exists long procId1 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes()), - nonceGroup, - nonce); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes())); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); // First delete should succeed @@ -142,9 +136,7 @@ public class TestDeleteColumnFamilyProcedure { // delete the column family that does not exist long procId2 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes()), - nonceGroup + 1, - nonce + 1); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes())); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); @@ -159,9 +151,7 @@ public class TestDeleteColumnFamilyProcedure { // Try again, this time with table disabled. UTIL.getHBaseAdmin().disableTable(tableName); long procId3 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes()), - nonceGroup + 2, - nonce + 2); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes())); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId3); // Expect fail with InvalidFamilyOperationException @@ -173,37 +163,6 @@ public class TestDeleteColumnFamilyProcedure { } @Test(timeout=60000) - public void testDeleteColumnFamilyTwiceWithSameNonce() throws Exception { - final TableName tableName = TableName.valueOf("testDeleteColumnFamilyTwiceWithSameNonce"); - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - - final String cf2 = "cf2"; - - MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", cf2); - - // delete the column family that exists - long procId1 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes()), - nonceGroup, - nonce); - long procId2 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf2.getBytes()), - nonceGroup, - nonce); - - // Wait the completion - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); - MasterProcedureTestingUtility.validateColumnFamilyDeletion(UTIL.getHBaseCluster().getMaster(), - tableName, cf2); - - // Wait the completion and expect not fail - because it is the same proc - ProcedureTestingUtility.waitProcedure(procExec, procId2); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); - assertTrue(procId1 == procId2); - } - - @Test(timeout=60000) public void testDeleteNonExistingColumnFamily() throws Exception { final TableName tableName = TableName.valueOf("testDeleteNonExistingColumnFamily"); final ProcedureExecutor procExec = getMasterProcedureExecutor(); @@ -214,9 +173,7 @@ public class TestDeleteColumnFamilyProcedure { // delete the column family that does not exist long procId1 = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf3.getBytes()), - nonceGroup, - nonce); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf3.getBytes())); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); @@ -242,9 +199,7 @@ public class TestDeleteColumnFamilyProcedure { // Start the Delete procedure && kill the executor long procId = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf4.getBytes()), - nonceGroup, - nonce); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf4.getBytes())); // Restart the executor and execute the step twice int numberOfSteps = DeleteColumnFamilyState.values().length; @@ -269,9 +224,7 @@ public class TestDeleteColumnFamilyProcedure { // Start the Delete procedure && kill the executor long procId = procExec.submitProcedure( - new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf5.getBytes()), - nonceGroup, - nonce); + new DeleteColumnFamilyProcedure(procExec.getEnvironment(), tableName, cf5.getBytes())); // Restart the executor and execute the step twice int numberOfSteps = DeleteColumnFamilyState.values().length; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java index e9fbddc..057216d 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java @@ -52,9 +52,6 @@ public class TestDeleteNamespaceProcedure { protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); - private static long nonceGroup = HConstants.NO_NONCE; - private static long nonce = HConstants.NO_NONCE; - private static void setupConf(Configuration conf) { conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); } @@ -77,9 +74,6 @@ public class TestDeleteNamespaceProcedure { @Before public void setup() throws Exception { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false); - nonceGroup = - MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster()); - nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster()); } @After @@ -99,9 +93,7 @@ public class TestDeleteNamespaceProcedure { createNamespaceForTesting(namespaceName); long procId = procExec.submitProcedure( - new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName), - nonceGroup, - nonce); + new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureTestingUtility.assertProcNotFailed(procExec, procId); @@ -117,9 +109,7 @@ public class TestDeleteNamespaceProcedure { validateNamespaceNotExist(namespaceName); long procId = procExec.submitProcedure( - new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName), - nonceGroup, - nonce); + new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); // Expect fail with NamespaceNotFoundException @@ -136,9 +126,7 @@ public class TestDeleteNamespaceProcedure { final ProcedureExecutor procExec = getMasterProcedureExecutor(); long procId = procExec.submitProcedure( - new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName), - nonceGroup, - nonce); + new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureInfo result = procExec.getResult(procId); @@ -158,9 +146,7 @@ public class TestDeleteNamespaceProcedure { MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1"); long procId = procExec.submitProcedure( - new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName), - nonceGroup, - nonce); + new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureInfo result = procExec.getResult(procId); @@ -169,33 +155,6 @@ public class TestDeleteNamespaceProcedure { assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException); } - @Test(timeout=60000) - public void testDeleteSameNamespaceTwiceWithSameNonce() throws Exception { - final String namespaceName = "testDeleteSameNamespaceTwiceWithSameNonce"; - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - - createNamespaceForTesting(namespaceName); - - long procId1 = procExec.submitProcedure( - new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName), - nonceGroup, - nonce); - long procId2 = procExec.submitProcedure( - new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName), - nonceGroup, - nonce); - // Wait the completion - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); - - validateNamespaceNotExist(namespaceName); - - // Wait the completion and expect not fail - because it is the same proc - ProcedureTestingUtility.waitProcedure(procExec, procId2); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); - assertTrue(procId1 == procId2); - } - @Test(timeout = 60000) public void testRecoveryAndDoubleExecution() throws Exception { final String namespaceName = "testRecoveryAndDoubleExecution"; @@ -208,9 +167,7 @@ public class TestDeleteNamespaceProcedure { // Start the DeleteNamespace procedure && kill the executor long procId = procExec.submitProcedure( - new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName), - nonceGroup, - nonce); + new DeleteNamespaceProcedure(procExec.getEnvironment(), namespaceName)); // Restart the executor and execute the step twice int numberOfSteps = DeleteNamespaceState.values().length; @@ -263,9 +220,7 @@ public class TestDeleteNamespaceProcedure { final ProcedureExecutor procExec = getMasterProcedureExecutor(); long procId = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup + 1, - nonce + 1); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureTestingUtility.assertProcNotFailed(procExec, procId); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteTableProcedure.java index 4a1c435..6d9fdfa 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteTableProcedure.java @@ -126,10 +126,10 @@ public class TestDeleteTableProcedure { // delete the table (that exists) long procId1 = procExec.submitProcedure( - new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce); + new DeleteTableProcedure(procExec.getEnvironment(), tableName)); // delete the table (that will no longer exist) long procId2 = procExec.submitProcedure( - new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup + 1, nonce + 1); + new DeleteTableProcedure(procExec.getEnvironment(), tableName)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); @@ -148,36 +148,6 @@ public class TestDeleteTableProcedure { } @Test(timeout=60000) - public void testDoubleDeletedTableWithSameNonce() throws Exception { - final TableName tableName = TableName.valueOf("testDoubleDeletedTableWithSameNonce"); - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - - HRegionInfo[] regions = MasterProcedureTestingUtility.createTable( - procExec, tableName, null, "f"); - UTIL.getHBaseAdmin().disableTable(tableName); - - // delete the table (that exists) - long procId1 = procExec.submitProcedure( - new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce); - // delete the table (that will no longer exist) - long procId2 = procExec.submitProcedure( - new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce); - - // Wait the completion - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.waitProcedure(procExec, procId2); - - // First delete should succeed - ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); - MasterProcedureTestingUtility.validateTableDeletion( - UTIL.getHBaseCluster().getMaster(), tableName, regions, "f"); - - // Second delete should not fail, because it is the same delete - ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); - assertTrue(procId1 == procId2); - } - - @Test(timeout=60000) public void testSimpleDelete() throws Exception { final TableName tableName = TableName.valueOf("testSimpleDelete"); final byte[][] splitKeys = null; @@ -223,7 +193,7 @@ public class TestDeleteTableProcedure { // Start the Delete procedure && kill the executor long procId = procExec.submitProcedure( - new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce); + new DeleteTableProcedure(procExec.getEnvironment(), tableName)); // Restart the executor and execute the step twice // NOTE: the 6 (number of DeleteTableState steps) is hardcoded, diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDisableTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDisableTableProcedure.java index 078db92..1d4a60d 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDisableTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDisableTableProcedure.java @@ -96,7 +96,7 @@ public class TestDisableTableProcedure { // Disable the table long procId = procExec.submitProcedure( - new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + new DisableTableProcedure(procExec.getEnvironment(), tableName, false)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureTestingUtility.assertProcNotFailed(procExec, procId); @@ -113,7 +113,7 @@ public class TestDisableTableProcedure { // Disable the table long procId1 = procExec.submitProcedure(new DisableTableProcedure( - procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + procExec.getEnvironment(), tableName, false)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); @@ -122,7 +122,7 @@ public class TestDisableTableProcedure { // Disable the table again - expect failure long procId2 = procExec.submitProcedure(new DisableTableProcedure( - procExec.getEnvironment(), tableName, false), nonceGroup + 1, nonce + 1); + procExec.getEnvironment(), tableName, false)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); ProcedureInfo result = procExec.getResult(procId2); @@ -136,7 +136,7 @@ public class TestDisableTableProcedure { final ProcedurePrepareLatch prepareLatch = new ProcedurePrepareLatch.CompatibilityLatch(); long procId3 = procExec.submitProcedure(new DisableTableProcedure( - procExec.getEnvironment(), tableName, false, prepareLatch), nonceGroup + 2, nonce + 2); + procExec.getEnvironment(), tableName, false, prepareLatch)); prepareLatch.await(); Assert.fail("Disable should throw exception through latch."); } catch (TableNotEnabledException tnee) { @@ -154,29 +154,6 @@ public class TestDisableTableProcedure { tableName); } - @Test(timeout = 60000) - public void testDisableTableTwiceWithSameNonce() throws Exception { - final TableName tableName = TableName.valueOf("testDisableTableTwiceWithSameNonce"); - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - - MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2"); - - // Disable the table - long procId1 = procExec.submitProcedure(new DisableTableProcedure( - procExec.getEnvironment(), tableName, false), nonceGroup, nonce); - long procId2 = procExec.submitProcedure(new DisableTableProcedure( - procExec.getEnvironment(), tableName, false), nonceGroup, nonce); - // Wait the completion - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); - MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(), - tableName); - - ProcedureTestingUtility.waitProcedure(procExec, procId2); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); - assertTrue(procId1 == procId2); - } - @Test(timeout=60000) public void testRecoveryAndDoubleExecution() throws Exception { final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution"); @@ -191,7 +168,7 @@ public class TestDisableTableProcedure { // Start the Disable procedure && kill the executor long procId = procExec.submitProcedure( - new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + new DisableTableProcedure(procExec.getEnvironment(), tableName, false)); // Restart the executor and execute the step twice int numberOfSteps = DisableTableState.values().length; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestEnableTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestEnableTableProcedure.java index 8200246..ce15e51 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestEnableTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestEnableTableProcedure.java @@ -97,7 +97,7 @@ public class TestEnableTableProcedure { // Enable the table long procId = procExec.submitProcedure( - new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + new EnableTableProcedure(procExec.getEnvironment(), tableName, false)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureTestingUtility.assertProcNotFailed(procExec, procId); @@ -105,29 +105,6 @@ public class TestEnableTableProcedure { tableName); } - @Test(timeout = 60000) - public void testEnableTableTwiceWithSameNonce() throws Exception { - final TableName tableName = TableName.valueOf("testEnableTableTwiceWithSameNonce"); - final ProcedureExecutor procExec = getMasterProcedureExecutor(); - - MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2"); - UTIL.getHBaseAdmin().disableTable(tableName); - - // Enable the table - long procId1 = procExec.submitProcedure( - new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); - long procId2 = procExec.submitProcedure( - new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); - - // Wait the completion - ProcedureTestingUtility.waitProcedure(procExec, procId1); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); - // The second proc should succeed too - because it is the same proc. - ProcedureTestingUtility.waitProcedure(procExec, procId2); - ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); - assertTrue(procId1 == procId2); - } - @Test(timeout=60000, expected=TableNotDisabledException.class) public void testEnableNonDisabledTable() throws Exception { final TableName tableName = TableName.valueOf("testEnableNonExistingTable"); @@ -137,7 +114,7 @@ public class TestEnableTableProcedure { // Enable the table - expect failure long procId1 = procExec.submitProcedure( - new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + new EnableTableProcedure(procExec.getEnvironment(), tableName, false)); ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureInfo result = procExec.getResult(procId1); @@ -148,9 +125,7 @@ public class TestEnableTableProcedure { // Enable the table with skipping table state check flag (simulate recovery scenario) long procId2 = procExec.submitProcedure( - new EnableTableProcedure(procExec.getEnvironment(), tableName, true), - nonceGroup + 1, - nonce + 1); + new EnableTableProcedure(procExec.getEnvironment(), tableName, true)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); @@ -158,9 +133,7 @@ public class TestEnableTableProcedure { // Enable the table - expect failure from ProcedurePrepareLatch final ProcedurePrepareLatch prepareLatch = new ProcedurePrepareLatch.CompatibilityLatch(); long procId3 = procExec.submitProcedure( - new EnableTableProcedure(procExec.getEnvironment(), tableName, false, prepareLatch), - nonceGroup + 2, - nonce + 2); + new EnableTableProcedure(procExec.getEnvironment(), tableName, false, prepareLatch)); prepareLatch.await(); Assert.fail("Enable should throw exception through latch."); } @@ -180,7 +153,7 @@ public class TestEnableTableProcedure { // Start the Enable procedure && kill the executor long procId = procExec.submitProcedure( - new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + new EnableTableProcedure(procExec.getEnvironment(), tableName, false)); // Restart the executor and execute the step twice int numberOfSteps = EnableTableState.values().length; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestMasterProcedureEvents.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestMasterProcedureEvents.java index adf3e5c..b6eaf38 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestMasterProcedureEvents.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestMasterProcedureEvents.java @@ -54,9 +54,6 @@ public class TestMasterProcedureEvents { protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); - private static long nonceGroup = HConstants.NO_NONCE; - private static long nonce = HConstants.NO_NONCE; - private static void setupConf(Configuration conf) { conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 8); conf.setBoolean(WALProcedureStore.USE_HSYNC_CONF_KEY, false); @@ -98,7 +95,7 @@ public class TestMasterProcedureEvents { long pollCalls = procSched.getPollCalls(); long nullPollCalls = procSched.getNullPollCalls(); - long procId = procExec.submitProcedure(proc, HConstants.NO_NONCE, HConstants.NO_NONCE); + long procId = procExec.submitProcedure(proc); for (int i = 0; i < 10; ++i) { Thread.sleep(100); assertEquals(pollCalls + 1, procSched.getPollCalls()); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyColumnFamilyProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyColumnFamilyProcedure.java index 12b2ad8..e38020a 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyColumnFamilyProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyColumnFamilyProcedure.java @@ -101,9 +101,7 @@ public class TestModifyColumnFamilyProcedure { // Test 1: modify the column family online columnDescriptor.setBlocksize(newBlockSize); long procId1 = procExec.submitProcedure( - new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); + new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); @@ -114,9 +112,7 @@ public class TestModifyColumnFamilyProcedure { UTIL.getHBaseAdmin().disableTable(tableName); columnDescriptor.setBlocksize(newBlockSize * 2); long procId2 = procExec.submitProcedure( - new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup + 1, - nonce + 1); + new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId2); ProcedureTestingUtility.assertProcNotFailed(procExec, procId2); @@ -139,9 +135,7 @@ public class TestModifyColumnFamilyProcedure { // Modify the column family that does not exist columnDescriptor.setBlocksize(newBlockSize); long procId1 = procExec.submitProcedure( - new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); + new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); @@ -171,9 +165,7 @@ public class TestModifyColumnFamilyProcedure { // Start the Modify procedure && kill the executor columnDescriptor.setBlocksize(newBlockSize); long procId = procExec.submitProcedure( - new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); + new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Restart the executor and execute the step twice int numberOfSteps = ModifyColumnFamilyState.values().length; @@ -205,9 +197,7 @@ public class TestModifyColumnFamilyProcedure { // Start the Modify procedure && kill the executor columnDescriptor.setBlocksize(newBlockSize); long procId = procExec.submitProcedure( - new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor), - nonceGroup, - nonce); + new ModifyColumnFamilyProcedure(procExec.getEnvironment(), tableName, columnDescriptor)); // Restart the executor and execute the step twice int numberOfSteps = ModifyColumnFamilyState.values().length; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyNamespaceProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyNamespaceProcedure.java index c38eab8..7f62554 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyNamespaceProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyNamespaceProcedure.java @@ -48,9 +48,6 @@ public class TestModifyNamespaceProcedure { protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); - private static long nonceGroup = HConstants.NO_NONCE; - private static long nonce = HConstants.NO_NONCE; - private static void setupConf(Configuration conf) { conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); } @@ -73,9 +70,6 @@ public class TestModifyNamespaceProcedure { @Before public void setup() throws Exception { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false); - nonceGroup = - MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster()); - nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster()); } @After @@ -112,9 +106,7 @@ public class TestModifyNamespaceProcedure { nsd.setConfiguration(nsKey2, nsValue2); long procId1 = procExec.submitProcedure( - new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId1); ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); @@ -142,9 +134,7 @@ public class TestModifyNamespaceProcedure { final NamespaceDescriptor nsd = NamespaceDescriptor.create(namespaceName).build(); long procId = procExec.submitProcedure( - new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); @@ -170,9 +160,7 @@ public class TestModifyNamespaceProcedure { nsd.setConfiguration(nsKey, nsValue); long procId = procExec.submitProcedure( - new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureInfo result = procExec.getResult(procId); @@ -195,9 +183,7 @@ public class TestModifyNamespaceProcedure { nsd.setConfiguration(nsKey, nsValue); long procId = procExec.submitProcedure( - new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureInfo result = procExec.getResult(procId); @@ -223,9 +209,7 @@ public class TestModifyNamespaceProcedure { // Start the Modify procedure && kill the executor long procId = procExec.submitProcedure( - new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd), - nonceGroup, - nonce); + new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); // Restart the executor and execute the step twice int numberOfSteps = ModifyNamespaceState.values().length; @@ -285,9 +269,7 @@ public class TestModifyNamespaceProcedure { final ProcedureExecutor procExec = getMasterProcedureExecutor(); long procId = procExec.submitProcedure( - new CreateNamespaceProcedure(procExec.getEnvironment(), nsDescriptor), - nonceGroup + 1, - nonce + 1); + new CreateNamespaceProcedure(procExec.getEnvironment(), nsDescriptor)); // Wait the completion ProcedureTestingUtility.waitProcedure(procExec, procId); ProcedureTestingUtility.assertProcNotFailed(procExec, procId); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java index ae43867..56902ee 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java @@ -251,7 +251,7 @@ public class TestModifyTableProcedure { // Start the Modify procedure && kill the executor long procId = procExec.submitProcedure( - new ModifyTableProcedure(procExec.getEnvironment(), htd), nonceGroup, nonce); + new ModifyTableProcedure(procExec.getEnvironment(), htd)); // Restart the executor and execute the step twice int numberOfSteps = ModifyTableState.values().length; @@ -293,7 +293,7 @@ public class TestModifyTableProcedure { // Start the Modify procedure && kill the executor long procId = procExec.submitProcedure( - new ModifyTableProcedure(procExec.getEnvironment(), htd), nonceGroup, nonce); + new ModifyTableProcedure(procExec.getEnvironment(), htd)); // Restart the executor and execute the step twice int numberOfSteps = ModifyTableState.values().length; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedureAdmin.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedureAdmin.java index 8097ae5..0010078 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedureAdmin.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedureAdmin.java @@ -49,9 +49,6 @@ public class TestProcedureAdmin { protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); - private long nonceGroup = HConstants.NO_NONCE; - private long nonce = HConstants.NO_NONCE; - private static void setupConf(Configuration conf) { conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); } @@ -76,10 +73,6 @@ public class TestProcedureAdmin { final ProcedureExecutor procExec = getMasterProcedureExecutor(); ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false); assertTrue("expected executor to be running", procExec.isRunning()); - - nonceGroup = - MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster()); - nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster()); } @After @@ -102,7 +95,7 @@ public class TestProcedureAdmin { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); // Submit an abortable procedure long procId = procExec.submitProcedure( - new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + new DisableTableProcedure(procExec.getEnvironment(), tableName, false)); // Wait for one step to complete ProcedureTestingUtility.waitProcedure(procExec, procId); @@ -129,7 +122,7 @@ public class TestProcedureAdmin { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); // Submit an un-abortable procedure long procId = procExec.submitProcedure( - new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce); + new DeleteTableProcedure(procExec.getEnvironment(), tableName)); // Wait for one step to complete ProcedureTestingUtility.waitProcedure(procExec, procId); @@ -155,7 +148,7 @@ public class TestProcedureAdmin { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); // Submit a procedure long procId = procExec.submitProcedure( - new DisableTableProcedure(procExec.getEnvironment(), tableName, true), nonceGroup, nonce); + new DisableTableProcedure(procExec.getEnvironment(), tableName, true)); // Wait for one step to complete ProcedureTestingUtility.waitProcedure(procExec, procId); @@ -196,7 +189,7 @@ public class TestProcedureAdmin { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); long procId = procExec.submitProcedure( - new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce); + new DisableTableProcedure(procExec.getEnvironment(), tableName, false)); // Wait for one step to complete ProcedureTestingUtility.waitProcedure(procExec, procId); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java index 7a3df0f..b201854 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java @@ -215,9 +215,7 @@ public class TestTruncateTableProcedure { // Start the Truncate procedure && kill the executor long procId = procExec.submitProcedure( - new TruncateTableProcedure(procExec.getEnvironment(), tableName, preserveSplits), - nonceGroup, - nonce); + new TruncateTableProcedure(procExec.getEnvironment(), tableName, preserveSplits)); // Restart the executor and execute the step twice // NOTE: the 7 (number of TruncateTableState steps) is hardcoded,