HBASE-17149 Procedure V2 - Fix nonce submission to avoid unnecessary calling 
coprocessor multiple times (Matteo Bertozzi)

Conflicts:
        
hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureExecutor.java
        
hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/ProcedureTestingUtility.java
        hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java

Conflicts:
        hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
        
hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java
        
hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java
        
hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java
        
hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java
        
hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java
        
hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java
        
hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyNamespaceProcedure.java
        
hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedureAdmin.java


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

Branch: refs/heads/branch-1.2
Commit: 28ec26035b3195fd0d78c212b23b9429d09f550f
Parents: 64f4171
Author: Stephen Yuan Jiang <[email protected]>
Authored: Wed Dec 28 15:43:50 2016 -0800
Committer: Stephen Yuan Jiang <[email protected]>
Committed: Wed Dec 28 20:42:28 2016 -0800

----------------------------------------------------------------------
 .../hbase/procedure2/ProcedureExecutor.java     | 156 +++++++--
 .../procedure2/ProcedureTestingUtility.java     |  23 +-
 .../hbase/procedure2/TestProcedureNonce.java    | 284 +++++++++++++++
 .../hbase/procedure2/TestProcedureRecovery.java |  43 ---
 .../org/apache/hadoop/hbase/master/HMaster.java | 350 +++++++++++--------
 .../master/procedure/MasterProcedureUtil.java   |  88 +++++
 .../procedure/TestAddColumnFamilyProcedure.java |  70 +---
 .../procedure/TestCreateTableProcedure.java     |  42 +--
 .../TestDeleteColumnFamilyProcedure.java        |  78 +----
 .../procedure/TestDeleteTableProcedure.java     |  44 +--
 .../procedure/TestDisableTableProcedure.java    |  40 +--
 .../procedure/TestEnableTableProcedure.java     |  46 +--
 .../procedure/TestMasterProcedureEvents.java    |  10 +-
 .../TestModifyColumnFamilyProcedure.java        |  31 +-
 .../procedure/TestModifyTableProcedure.java     |  17 +-
 .../master/procedure/TestProcedureAdmin.java    |  16 +-
 .../procedure/TestTruncateTableProcedure.java   |  12 +-
 17 files changed, 765 insertions(+), 585 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/ProcedureExecutor.java
----------------------------------------------------------------------
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 37bcb00..b4a388a 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
@@ -52,8 +52,10 @@ 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.base.Preconditions;
 
@@ -610,59 +612,143 @@ public class ProcedureExecutor<TEnvironment> {
     return procedureLists;
   }
 
+  // ==========================================================================
+  //  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
+  // ==========================================================================
+  /**
+>>>>>>> ce33cf2... HBASE-17149 Procedure V2 - Fix nonce submission to avoid 
unnecessary calling coprocessor multiple times (Matteo Bertozzi)
    * 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);
   }
 
   /**
    * Add a new root-procedure to the executor.
    * @param proc the new procedure to execute.
-   * @param nonceGroup
-   * @param nonce
+   * @param nonceKey the registered unique identifier for this operation from 
the client or process.
    * @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(isRunning(), "executor not running");
     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;
-        }
-      }
+    Preconditions.checkArgument(!proc.hasParent(), "unexpected parent", proc);
 
-      // 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);

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/ProcedureTestingUtility.java
----------------------------------------------------------------------
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 ddddf41..64726ba 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
@@ -32,7 +32,6 @@ import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.ProcedureInfo;
 import org.apache.hadoop.hbase.io.util.StreamUtils;
-import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos;
 import org.apache.hadoop.hbase.util.Threads;
 import org.apache.hadoop.hbase.exceptions.IllegalArgumentIOException;
 import org.apache.hadoop.hbase.exceptions.TimeoutIOException;
@@ -41,7 +40,8 @@ import 
org.apache.hadoop.hbase.procedure2.store.ProcedureStore.ProcedureIterator
 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;
+import org.apache.hadoop.hbase.util.NonceKey;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -140,13 +140,20 @@ public class ProcedureTestingUtility {
   }
 
   public static <TEnv> long submitAndWait(ProcedureExecutor<TEnv> 
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 <TEnv> long submitProcedure(ProcedureExecutor<TEnv> 
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 <TEnv> void waitProcedure(ProcedureExecutor<TEnv> 
procExecutor, long procId) {
     while (!procExecutor.isFinished(procId) && procExecutor.isRunning()) {
       Threads.sleepWithoutInterrupt(250);
@@ -185,6 +192,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());

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureNonce.java
----------------------------------------------------------------------
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..1fbd0ee
--- /dev/null
+++ 
b/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureNonce.java
@@ -0,0 +1,284 @@
+/**
+ * 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;
+
+@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<TestProcEnv> 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<Throwable> t1Exception = new AtomicReference();
+    final AtomicReference<Throwable> 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<TestProcEnv> {
+    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

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-procedure/src/test/java/org/apache/hadoop/hbase/procedure2/TestProcedureRecovery.java
----------------------------------------------------------------------
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 9e01fcf..5bcc47f 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<TestProcEnv, 
TestStateMachineProcedure.State> {
     enum State { STATE_1, STATE_2, STATE_3, DONE }

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
----------------------------------------------------------------------
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 a53c236..239c94c 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
@@ -108,6 +108,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.ModifyTableProcedure;
 import org.apache.hadoop.hbase.master.procedure.ProcedurePrepareLatch;
 import org.apache.hadoop.hbase.master.procedure.ProcedureSyncWait;
@@ -1497,30 +1498,34 @@ public class HMaster extends HRegionServer implements 
MasterServices, Server {
     String namespace = hTableDescriptor.getTableName().getNamespaceAsString();
     ensureNamespaceExists(namespace);
 
-    HRegionInfo[] newRegions = 
ModifyRegionUtils.createHRegionInfos(hTableDescriptor, splitKeys);
+    final HRegionInfo[] newRegions =
+        ModifyRegionUtils.createHRegionInfos(hTableDescriptor, splitKeys);
     checkInitialized();
     sanityCheckTableDescriptor(hTableDescriptor);
 
-    if (cpHost != null) {
-      cpHost.preCreateTable(hTableDescriptor, newRegions);
-    }
-    LOG.info(getClientIdAuditPrefix() + " create " + hTableDescriptor);
+    return MasterProcedureUtil.submitProcedure(
+      new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
+      @Override
+      protected void run() throws IOException {
+        
getMaster().getMasterCoprocessorHost().preCreateTable(hTableDescriptor, 
newRegions);
 
-    // 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();
+        LOG.info(getClientIdAuditPrefix() + " create " + hTableDescriptor);
 
-    if (cpHost != null) {
-      cpHost.postCreateTable(hTableDescriptor, newRegions);
-    }
+        // 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);
+      }
 
-    return procId;
+      @Override
+      protected String getDescription() {
+        return "CreateTableProcedure";
+      }
+    });
   }
 
   /**
@@ -1827,24 +1832,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
@@ -1854,20 +1864,27 @@ 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);
 
-    if (cpHost != null) {
-      cpHost.postTruncateTable(tableName);
-    }
+        LOG.info(getClientIdAuditPrefix() + " truncate " + tableName);
+
+        long procId = submitProcedure(new 
TruncateTableProcedure(procedureExecutor.getEnvironment(),
+            tableName, preserveSplits));
+        ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, 
procId);
+
+        getMaster().getMasterCoprocessorHost().postTruncateTable(tableName);
+      }
+
+      @Override
+      protected String getDescription() {
+        return "TruncateTableProcedure";
+      }
+    });
   }
 
   @Override
@@ -1880,20 +1897,28 @@ public class HMaster extends HRegionServer implements 
MasterServices, Server {
     checkInitialized();
     checkCompression(columnDescriptor);
     checkEncryption(conf, 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
+        long procId = submitProcedure(new AddColumnFamilyProcedure(
+          procedureExecutor.getEnvironment(), tableName, columnDescriptor));
+        ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, 
procId);
+
+        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
@@ -1906,23 +1931,30 @@ public class HMaster extends HRegionServer implements 
MasterServices, Server {
     checkInitialized();
     checkCompression(descriptor);
     checkEncryption(conf, descriptor);
-    if (cpHost != null) {
-      if (cpHost.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);
+    MasterProcedureUtil.submitProcedure(
+      new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
+      @Override
+      protected void run() throws IOException {
+        if (getMaster().getMasterCoprocessorHost().preModifyColumn(tableName, 
descriptor)) {
+          return;
+        }
 
-    if (cpHost != null) {
-      cpHost.postModifyColumn(tableName, descriptor);
-    }
+        LOG.info(getClientIdAuditPrefix() + " modify " + descriptor);
+
+        // Execute the operation synchronously - wait for the operation to 
complete before continuing.
+        long procId = submitProcedure(new ModifyColumnFamilyProcedure(
+          procedureExecutor.getEnvironment(), tableName, descriptor));
+        ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, 
procId);
+
+        getMaster().getMasterCoprocessorHost().postModifyColumn(tableName, 
descriptor);
+      }
+
+      @Override
+      protected String getDescription() {
+        return "ModifyColumnFamilyProcedure";
+      }
+    });
   }
 
   @Override
@@ -1933,84 +1965,97 @@ 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));
 
-    // 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);
+    MasterProcedureUtil.submitProcedure(
+      new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
+      @Override
+      protected void run() throws IOException {
+        if (getMaster().getMasterCoprocessorHost().preDeleteColumn(tableName, 
columnName)) {
+          return;
+        }
 
-    if (cpHost != null) {
-      cpHost.postDeleteColumn(tableName, columnName);
-    }
+        LOG.info(getClientIdAuditPrefix() + " delete " + 
Bytes.toString(columnName));
+
+        // Execute the operation synchronously - wait for the operation to 
complete before
+        // continuing.
+        long procId = submitProcedure(new DeleteColumnFamilyProcedure(
+          procedureExecutor.getEnvironment(), tableName, columnName));
+        ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, 
procId);
+
+        getMaster().getMasterCoprocessorHost().postDeleteColumn(tableName, 
columnName);
+      }
+
+      @Override
+      protected String getDescription() {
+        return "DeleteColumnFamilyProcedure";
+      }
+    });
   }
 
   @Override
-  public long enableTable(
-      final TableName tableName,
-      final long nonceGroup,
-      final long nonce) throws IOException {
+  public long enableTable(final TableName tableName, 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 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);
+      }
 
-    return procId;
+      @Override
+      protected String getDescription() {
+        return "EnableTableProcedure";
+      }
+    });
   }
 
   @Override
-  public long disableTable(
-      final TableName tableName,
-      final long nonceGroup,
-      final long nonce) throws IOException {
+  public long disableTable(final TableName tableName, 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 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);
+      }
 
-    return procId;
+      @Override
+      protected String getDescription() {
+        return "DisableTableProcedure";
+      }
+    });
   }
 
   /**
@@ -2058,23 +2103,28 @@ public class HMaster extends HRegionServer implements 
MasterServices, Server {
       throws IOException {
     checkInitialized();
     sanityCheckTableDescriptor(descriptor);
-    if (cpHost != null) {
-      cpHost.preModifyTable(tableName, descriptor);
-    }
 
-    LOG.info(getClientIdAuditPrefix() + " modify " + tableName);
+    MasterProcedureUtil.submitProcedure(
+      new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
+      @Override
+      protected void run() throws IOException {
+        getMaster().getMasterCoprocessorHost().preModifyTable(tableName, 
descriptor);
 
-    // Execute the operation synchronously - wait for the operation completes 
before continuing.
-    long procId = this.procedureExecutor.submitProcedure(
-      new ModifyTableProcedure(procedureExecutor.getEnvironment(), descriptor),
-      nonceGroup,
-      nonce);
+        LOG.info(getClientIdAuditPrefix() + " modify " + tableName);
 
-    ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, procId);
+        // Execute the operation synchronously - wait for the operation 
completes before continuing.
+        long procId = submitProcedure(new ModifyTableProcedure(
+          procedureExecutor.getEnvironment(), descriptor));
+        ProcedureSyncWait.waitForProcedureToComplete(procedureExecutor, 
procId);
 
-    if (cpHost != null) {
-      cpHost.postModifyTable(tableName, descriptor);
-    }
+        getMaster().getMasterCoprocessorHost().postModifyTable(tableName, 
descriptor);
+      }
+
+      @Override
+      protected String getDescription() {
+        return "ModifyTableProcedure";
+      }
+    });
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java
----------------------------------------------------------------------
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..4759e7d 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,11 +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.hbase.security.User;
+import org.apache.hadoop.hbase.util.NonceKey;
 import org.apache.hadoop.security.UserGroupInformation;
 
 @InterfaceAudience.Private
@@ -53,4 +60,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<MasterProcedureEnv> 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.
+   * <code>
+   * long procId = MasterProcedureUtil.submitProcedure(
+   *      new NonceProcedureRunnable(procExec, nonceGroup, nonce) {
+   *   {@literal @}Override
+   *   public void run() {
+   *     cpHost.preOperation();
+   *     submitProcedure(new MyProc());
+   *     cpHost.postOperation();
+   *   }
+   * });
+   * </code>
+   */
+  public static long submitProcedure(final NonceProcedureRunnable runnable) 
throws IOException {
+    final ProcedureExecutor<MasterProcedureEnv> 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();
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestAddColumnFamilyProcedure.java
----------------------------------------------------------------------
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..b3fa10a 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
@@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.HColumnDescriptor;
-import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.InvalidFamilyOperationException;
 import org.apache.hadoop.hbase.ProcedureInfo;
@@ -47,9 +46,6 @@ public class TestAddColumnFamilyProcedure {
 
   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);
   }
@@ -72,9 +68,6 @@ public class TestAddColumnFamilyProcedure {
   @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 +92,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 +103,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 +123,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 +132,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 +146,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 +158,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<MasterProcedureEnv> 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 +173,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 +198,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;
@@ -275,9 +223,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));
 
     int numberOfSteps = AddColumnFamilyState.values().length - 2; // failing 
in the middle of proc
     MasterProcedureTestingUtility.testRollbackAndDoubleExecution(procExec, 
procId, numberOfSteps,

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java
----------------------------------------------------------------------
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 73843e0..955a4e0 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
@@ -24,7 +24,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
-import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.TableExistsException;
@@ -50,9 +49,6 @@ public class TestCreateTableProcedure {
 
   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);
   }
@@ -75,9 +71,6 @@ public class TestCreateTableProcedure {
   @Before
   public void setup() throws Exception {
     resetProcExecutorTestingKillFlag();
-    nonceGroup =
-        
MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster());
-    nonce = 
MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster());
   }
 
   @After
@@ -127,14 +120,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));
@@ -144,29 +135,6 @@ public class TestCreateTableProcedure {
   }
 
   @Test(timeout=60000)
-  public void testCreateTwiceWithSameNonce() throws Exception {
-    final TableName tableName = 
TableName.valueOf("testCreateTwiceWithSameNonce");
-    final ProcedureExecutor<MasterProcedureEnv> 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");
 
@@ -179,7 +147,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,
@@ -207,7 +175,7 @@ public class TestCreateTableProcedure {
     htd.setRegionReplication(3);
     HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, 
splitKeys);
     long procId = procExec.submitProcedure(
-      new CreateTableProcedure(procExec.getEnvironment(), htd, regions), 
nonceGroup, nonce);
+      new CreateTableProcedure(procExec.getEnvironment(), htd, regions));
 
     // NOTE: the 4 (number of CreateTableState steps) is hardcoded,
     //       so you have to look at this test at least once when you add a new 
step.
@@ -237,7 +205,7 @@ public class TestCreateTableProcedure {
     HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, 
"f1", "f2");
     HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, 
splitKeys);
     long procId = procExec.submitProcedure(
-      new FaultyCreateTableProcedure(procExec.getEnvironment(), htd, regions), 
nonceGroup, nonce);
+      new CreateTableProcedure(procExec.getEnvironment(), htd, regions));
 
     // NOTE: the 4 (number of CreateTableState steps) is hardcoded,
     //       so you have to look at this test at least once when you add a new 
step.

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteColumnFamilyProcedure.java
----------------------------------------------------------------------
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..11d6f14 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
@@ -24,7 +24,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
-import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.InvalidFamilyOperationException;
@@ -47,9 +46,6 @@ public class TestDeleteColumnFamilyProcedure {
 
   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);
   }
@@ -72,9 +68,6 @@ public class TestDeleteColumnFamilyProcedure {
   @Before
   public void setup() throws Exception {
     
ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(),
 false);
-    nonceGroup =
-        
MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster());
-    nonce = 
MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster());
   }
 
   @After
@@ -97,9 +90,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 +101,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 +118,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 +129,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 +144,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 +156,6 @@ public class TestDeleteColumnFamilyProcedure {
   }
 
   @Test(timeout=60000)
-  public void testDeleteColumnFamilyTwiceWithSameNonce() throws Exception {
-    final TableName tableName = 
TableName.valueOf("testDeleteColumnFamilyTwiceWithSameNonce");
-    final ProcedureExecutor<MasterProcedureEnv> 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<MasterProcedureEnv> procExec = 
getMasterProcedureExecutor();
@@ -214,9 +166,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 +192,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 +217,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;
@@ -297,9 +243,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()));
 
     // Failing before DELETE_COLUMN_FAMILY_DELETE_FS_LAYOUT we should trigger 
the rollback
     // NOTE: the 1 (number before DELETE_COLUMN_FAMILY_DELETE_FS_LAYOUT step) 
is hardcoded,
@@ -330,9 +274,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()));
 
     // Failing after DELETE_COLUMN_FAMILY_DELETE_FS_LAYOUT we should not 
trigger the rollback.
     // NOTE: the 4 (number of DELETE_COLUMN_FAMILY_DELETE_FS_LAYOUT + 1 step) 
is hardcoded,

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteTableProcedure.java
----------------------------------------------------------------------
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..5ac0ea1 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
@@ -22,7 +22,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
-import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.ProcedureInfo;
@@ -49,9 +48,6 @@ public class TestDeleteTableProcedure {
 
   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 +72,6 @@ public class TestDeleteTableProcedure {
     final ProcedureExecutor<MasterProcedureEnv> 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
@@ -126,10 +118,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 +140,6 @@ public class TestDeleteTableProcedure {
   }
 
   @Test(timeout=60000)
-  public void testDoubleDeletedTableWithSameNonce() throws Exception {
-    final TableName tableName = 
TableName.valueOf("testDoubleDeletedTableWithSameNonce");
-    final ProcedureExecutor<MasterProcedureEnv> 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 +185,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,

http://git-wip-us.apache.org/repos/asf/hbase/blob/28ec2603/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDisableTableProcedure.java
----------------------------------------------------------------------
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..72d8113 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
@@ -24,7 +24,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
-import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.ProcedureInfo;
 import org.apache.hadoop.hbase.TableName;
@@ -48,9 +47,6 @@ public class TestDisableTableProcedure {
 
   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 +69,6 @@ public class TestDisableTableProcedure {
   @Before
   public void setup() throws Exception {
     
ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(),
 false);
-    nonceGroup =
-        
MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster());
-    nonce = 
MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster());
   }
 
   @After
@@ -96,7 +89,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 +106,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 +115,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 +129,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 +147,6 @@ public class TestDisableTableProcedure {
       tableName);
   }
 
-  @Test(timeout = 60000)
-  public void testDisableTableTwiceWithSameNonce() throws Exception {
-    final TableName tableName = 
TableName.valueOf("testDisableTableTwiceWithSameNonce");
-    final ProcedureExecutor<MasterProcedureEnv> 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 +161,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;

Reply via email to