You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by dr...@apache.org on 2015/08/18 04:14:10 UTC

curator git commit: Merge 'CURATOR-217' into CURATOR-3.0

Repository: curator
Updated Branches:
  refs/heads/217-merged [created] d5d12c88b


Merge 'CURATOR-217' into CURATOR-3.0


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

Branch: refs/heads/217-merged
Commit: d5d12c88b075fd1fc51a29412b3c08918cceb983
Parents: 44ee854 f0a09db
Author: Scott Blum <dr...@apache.org>
Authored: Mon Aug 17 22:13:37 2015 -0400
Committer: Scott Blum <dr...@apache.org>
Committed: Mon Aug 17 22:13:37 2015 -0400

----------------------------------------------------------------------
 .../org/apache/curator/utils/DebugUtils.java    |   1 +
 .../curator/framework/CuratorFramework.java     |  19 +
 .../WatcherRemoveCuratorFramework.java          |  30 +
 .../api/BackgroundPathableQuietly.java          |  23 +
 .../api/BackgroundPathableQuietlyable.java      |   5 +
 .../curator/framework/api/CuratorEventType.java |   5 +
 .../curator/framework/api/DeleteBuilder.java    |   2 +-
 .../curator/framework/api/Guaranteeable.java    |  20 +-
 .../framework/api/GuaranteeableDeletable.java   |  39 ++
 .../apache/curator/framework/api/Quietly.java   |  24 +
 .../framework/api/RemoveWatchesBuilder.java     |  47 ++
 .../framework/api/RemoveWatchesLocal.java       |  35 +
 .../framework/api/RemoveWatchesType.java        |  37 ++
 .../framework/imps/CuratorFrameworkImpl.java    |  28 +-
 .../framework/imps/DeleteBuilderImpl.java       |   4 +-
 .../framework/imps/ExistsBuilderImpl.java       |   4 +-
 .../framework/imps/FailedDeleteManager.java     |  39 +-
 .../framework/imps/FailedOperationManager.java  |  68 ++
 .../imps/FailedRemoveWatchManager.java          |  56 ++
 .../framework/imps/GetChildrenBuilderImpl.java  |   4 +-
 .../framework/imps/GetConfigBuilderImpl.java    |   5 +-
 .../framework/imps/GetDataBuilderImpl.java      |   4 +-
 .../framework/imps/OperationAndData.java        |  16 +-
 .../imps/RemoveWatchesBuilderImpl.java          | 315 +++++++++
 .../framework/imps/WatcherRemovalFacade.java    | 176 +++++
 .../framework/imps/WatcherRemovalManager.java   | 137 ++++
 .../apache/curator/framework/imps/Watching.java |   6 +-
 .../framework/imps/TestFailedDeleteManager.java |   9 +-
 .../framework/imps/TestRemoveWatches.java       | 655 +++++++++++++++++++
 .../imps/TestWatcherRemovalManager.java         | 257 ++++++++
 .../framework/recipes/cache/NodeCache.java      |   6 +-
 .../recipes/cache/PathChildrenCache.java        |  13 +-
 .../framework/recipes/cache/TreeCache.java      |   6 +-
 .../framework/recipes/leader/LeaderLatch.java   |   6 +-
 .../locks/InterProcessSemaphoreMutex.java       |   6 +-
 .../recipes/locks/InterProcessSemaphoreV2.java  |  60 +-
 .../framework/recipes/locks/LockInternals.java  |   9 +-
 .../recipes/nodes/PersistentEphemeralNode.java  |   7 +-
 .../framework/recipes/queue/ChildrenCache.java  |   6 +-
 .../framework/recipes/shared/SharedValue.java   |   8 +-
 .../curator/framework/imps/TestCleanState.java  |  68 ++
 .../recipes/cache/BaseTestTreeCache.java        |   3 +-
 .../framework/recipes/cache/TestNodeCache.java  |   9 +-
 .../recipes/cache/TestPathChildrenCache.java    |  58 +-
 .../recipes/leader/TestLeaderLatch.java         |  26 +-
 .../locks/TestInterProcessMultiMutex.java       |   7 +-
 .../recipes/locks/TestInterProcessMutex.java    |   5 +-
 .../locks/TestInterProcessMutexBase.java        |  19 +-
 .../locks/TestInterProcessReadWriteLock.java    | 223 ++++---
 .../locks/TestInterProcessSemaphore.java        |  27 +-
 .../locks/TestInterProcessSemaphoreCluster.java |   3 +-
 .../framework/recipes/locks/TestLockACLs.java   |   3 +-
 .../locks/TestLockCleanlinessWithFaults.java    |   3 +-
 .../nodes/TestPersistentEphemeralNode.java      |  18 +-
 .../recipes/shared/TestSharedCount.java         |  11 +-
 .../apache/curator/test/BaseClassForTests.java  |  14 +
 .../org/apache/curator/test/WatchersDebug.java  |  92 +++
 57 files changed, 2491 insertions(+), 295 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-client/src/main/java/org/apache/curator/utils/DebugUtils.java
----------------------------------------------------------------------
diff --cc curator-client/src/main/java/org/apache/curator/utils/DebugUtils.java
index b098989,e84e06b..383bc13
--- a/curator-client/src/main/java/org/apache/curator/utils/DebugUtils.java
+++ b/curator-client/src/main/java/org/apache/curator/utils/DebugUtils.java
@@@ -23,7 -23,7 +23,8 @@@ public class DebugUtil
      public static final String          PROPERTY_LOG_EVENTS = "curator-log-events";
      public static final String          PROPERTY_DONT_LOG_CONNECTION_ISSUES = "curator-dont-log-connection-problems";
      public static final String          PROPERTY_LOG_ONLY_FIRST_CONNECTION_ISSUE_AS_ERROR_LEVEL = "curator-log-only-first-connection-issue-as-error-level";
+     public static final String          PROPERTY_REMOVE_WATCHERS_IN_FOREGROUND = "curator-remove-watchers-in-foreground";
 +    public static final String          PROPERTY_RETRY_FAILED_TESTS = "curator-retry-failed-tests";
  
      private DebugUtils()
      {

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java
index 9239ac4,7de6308..58c5bf5
--- a/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java
@@@ -1,281 -1,251 +1,300 @@@
 -/**
 - * 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.curator.framework;
 -
 -import org.apache.curator.CuratorZookeeperClient;
 -import org.apache.curator.framework.api.*;
 -import org.apache.curator.framework.api.transaction.CuratorTransaction;
 -import org.apache.curator.framework.imps.CuratorFrameworkState;
 -import org.apache.curator.framework.listen.Listenable;
 -import org.apache.curator.framework.state.ConnectionStateListener;
 -import org.apache.curator.utils.EnsurePath;
 -import org.apache.zookeeper.Watcher;
 -
 -import java.io.Closeable;
 -import java.util.concurrent.TimeUnit;
 -
 -/**
 - * Zookeeper framework-style client
 - */
 -public interface CuratorFramework extends Closeable
 -{
 -    /**
 -     * Start the client. Most mutator methods will not work until the client is started
 -     */
 -    public void start();
 -
 -    /**
 -     * Stop the client
 -     */
 -    public void close();
 -
 -    /**
 -     * Returns the state of this instance
 -     *
 -     * @return state
 -     */
 -    public CuratorFrameworkState getState();
 -
 -    /**
 -     * Return true if the client is started, not closed, etc.
 -     *
 -     * @return true/false
 -     * @deprecated use {@link #getState()} instead
 -     */
 -    public boolean isStarted();
 -
 -    /**
 -     * Start a create builder
 -     *
 -     * @return builder object
 -     */
 -    public CreateBuilder create();
 -
 -    /**
 -     * Start a delete builder
 -     *
 -     * @return builder object
 -     */
 -    public DeleteBuilder delete();
 -
 -    /**
 -     * Start an exists builder
 -     * <p>
 -     * The builder will return a Stat object as if org.apache.zookeeper.ZooKeeper.exists() were called.  Thus, a null
 -     * means that it does not exist and an actual Stat object means it does exist.
 -     *
 -     * @return builder object
 -     */
 -    public ExistsBuilder checkExists();
 -
 -    /**
 -     * Start a get data builder
 -     *
 -     * @return builder object
 -     */
 -    public GetDataBuilder getData();
 -
 -    /**
 -     * Start a set data builder
 -     *
 -     * @return builder object
 -     */
 -    public SetDataBuilder setData();
 -
 -    /**
 -     * Start a get children builder
 -     *
 -     * @return builder object
 -     */
 -    public GetChildrenBuilder getChildren();
 -
 -    /**
 -     * Start a get ACL builder
 -     *
 -     * @return builder object
 -     */
 -    public GetACLBuilder getACL();
 -
 -    /**
 -     * Start a set ACL builder
 -     *
 -     * @return builder object
 -     */
 -    public SetACLBuilder setACL();
 -
 -    /**
 -     * Start a transaction builder
 -     *
 -     * @return builder object
 -     */
 -    public CuratorTransaction inTransaction();
 -
 -    /**
 -     * Perform a sync on the given path - syncs are always in the background
 -     *
 -     * @param path                    the path
 -     * @param backgroundContextObject optional context
 -     * @deprecated use {@link #sync()} instead
 -     */
 -    public void sync(String path, Object backgroundContextObject);
 -
 -    /**
 -     * Start a sync builder. Note: sync is ALWAYS in the background even
 -     * if you don't use one of the background() methods
 -     *
 -     * @return builder object
 -     */
 -    public SyncBuilder sync();
 -
 -    /**
 -     * Start a remove watches builder.
 -     * @return builder object
 -     */
 -    public RemoveWatchesBuilder watches();    
 -
 -    /**
 -     * Returns the listenable interface for the Connect State
 -     *
 -     * @return listenable
 -     */
 -    public Listenable<ConnectionStateListener> getConnectionStateListenable();
 -
 -    /**
 -     * Returns the listenable interface for events
 -     *
 -     * @return listenable
 -     */
 -    public Listenable<CuratorListener> getCuratorListenable();
 -
 -    /**
 -     * Returns the listenable interface for unhandled errors
 -     *
 -     * @return listenable
 -     */
 -    public Listenable<UnhandledErrorListener> getUnhandledErrorListenable();
 -
 -    /**
 -     * Returns a facade of the current instance that does _not_ automatically
 -     * pre-pend the namespace to all paths
 -     *
 -     * @return facade
 -     * @deprecated use {@link #usingNamespace} passing <code>null</code>
 -     */
 -    public CuratorFramework nonNamespaceView();
 -
 -    /**
 -     * Returns a facade of the current instance that uses the specified namespace
 -     * or no namespace if <code>newNamespace</code> is <code>null</code>.
 -     *
 -     * @param newNamespace the new namespace or null for none
 -     * @return facade
 -     */
 -    public CuratorFramework usingNamespace(String newNamespace);
 -
 -    /**
 -     * Return the current namespace or "" if none
 -     *
 -     * @return namespace
 -     */
 -    public String getNamespace();
 -
 -    /**
 -     * Return the managed zookeeper client
 -     *
 -     * @return client
 -     */
 -    public CuratorZookeeperClient getZookeeperClient();
 -
 -    /**
 -     * Allocates an ensure path instance that is namespace aware
 -     *
 -     * @param path path to ensure
 -     * @return new EnsurePath instance
 -     */
 -    public EnsurePath newNamespaceAwareEnsurePath(String path);
 -
 -    /**
 -     * Curator can hold internal references to watchers that may inhibit garbage collection.
 -     * Call this method on watchers you are no longer interested in.
 -     *
 -     * @param watcher the watcher
 -     * 
 -     * @deprecated As of ZooKeeper 3.5 Curators recipes will handle removing watcher references
 -     * when they are no longer used.
 -     */
 -    @Deprecated
 -    public void clearWatcherReferences(Watcher watcher);
 -        
 -    /**
 -     * Block until a connection to ZooKeeper is available or the maxWaitTime has been exceeded
 -     * @param maxWaitTime The maximum wait time. Specify a value &lt;= 0 to wait indefinitely
 -     * @param units The time units for the maximum wait time.
 -     * @return True if connection has been established, false otherwise.
 -     * @throws InterruptedException If interrupted while waiting
 -     */
 -    public boolean blockUntilConnected(int maxWaitTime, TimeUnit units) throws InterruptedException;
 -    
 -    /**
 -     * Block until a connection to ZooKeeper is available. This method will not return until a
 -     * connection is available or it is interrupted, in which case an InterruptedException will
 -     * be thrown
 -     * @throws InterruptedException If interrupted while waiting
 -     */
 -    public void blockUntilConnected() throws InterruptedException;
 -
 -    /**
 -     * Returns a facade of the current instance that tracks
 -     * watchers created and allows a one-shot removal of all watchers
 -     * via {@link WatcherRemoveCuratorFramework#removeWatchers()}
 -     *
 -     * @return facade
 -     */
 -    public WatcherRemoveCuratorFramework newWatcherRemoveCuratorFramework();
 -}
 +/**
 + * 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.curator.framework;
 +
 +import org.apache.curator.CuratorZookeeperClient;
 +import org.apache.curator.framework.api.*;
 +import org.apache.curator.framework.api.transaction.CuratorMultiTransaction;
 +import org.apache.curator.framework.api.transaction.CuratorOp;
 +import org.apache.curator.framework.api.transaction.CuratorTransaction;
 +import org.apache.curator.framework.api.transaction.TransactionOp;
 +import org.apache.curator.framework.imps.CuratorFrameworkState;
 +import org.apache.curator.framework.listen.Listenable;
 +import org.apache.curator.framework.state.ConnectionStateListener;
 +import org.apache.curator.utils.EnsurePath;
 +import org.apache.zookeeper.Watcher;
 +
 +import java.io.Closeable;
 +import java.util.concurrent.TimeUnit;
 +
 +/**
 + * Zookeeper framework-style client
 + */
 +public interface CuratorFramework extends Closeable
 +{
 +    /**
 +     * Start the client. Most mutator methods will not work until the client is started
 +     */
 +    public void start();
 +
 +    /**
 +     * Stop the client
 +     */
 +    public void close();
 +
 +    /**
 +     * Returns the state of this instance
 +     *
 +     * @return state
 +     */
 +    public CuratorFrameworkState getState();
 +
 +    /**
 +     * Return true if the client is started, not closed, etc.
 +     *
 +     * @return true/false
 +     * @deprecated use {@link #getState()} instead
 +     */
 +    @Deprecated
 +    public boolean isStarted();
 +
 +    /**
 +     * Start a create builder
 +     *
 +     * @return builder object
 +     */
 +    public CreateBuilder create();
 +
 +    /**
 +     * Start a delete builder
 +     *
 +     * @return builder object
 +     */
 +    public DeleteBuilder delete();
 +
 +    /**
 +     * Start an exists builder
 +     * <p>
 +     * The builder will return a Stat object as if org.apache.zookeeper.ZooKeeper.exists() were called.  Thus, a null
 +     * means that it does not exist and an actual Stat object means it does exist.
 +     *
 +     * @return builder object
 +     */
 +    public ExistsBuilder checkExists();
 +
 +    /**
 +     * Start a get data builder
 +     *
 +     * @return builder object
 +     */
 +    public GetDataBuilder getData();
 +
 +    /**
 +     * Start a set data builder
 +     *
 +     * @return builder object
 +     */
 +    public SetDataBuilder setData();
 +
 +    /**
 +     * Start a get children builder
 +     *
 +     * @return builder object
 +     */
 +    public GetChildrenBuilder getChildren();
 +
 +    /**
 +     * Start a get ACL builder
 +     *
 +     * @return builder object
 +     */
 +    public GetACLBuilder getACL();
 +
 +    /**
 +     * Start a set ACL builder
 +     *
 +     * @return builder object
 +     */
 +    public SetACLBuilder setACL();
 +
 +    /**
 +     * Start a reconfig builder
 +     *
 +     * @return builder object
 +     */
 +    public ReconfigBuilder reconfig();
 +
 +    /**
 +     * Start a getConfig builder
 +     *
 +     * @return builder object
 +     */
 +    public GetConfigBuilder getConfig();
 +
 +    /**
 +     * Start a transaction builder
 +     *
 +     * @return builder object
 +     * @deprecated use {@link #transaction()} instead
 +     */
 +    public CuratorTransaction inTransaction();
 +
 +    /**
 +     * Start a transaction builder
 +     *
 +     * @return builder object
 +     */
 +    public CuratorMultiTransaction transaction();
 +
 +    /**
 +     * Allocate an operation that can be used with {@link #transaction()}.
 +     * NOTE: {@link CuratorOp} instances created by this builder are
 +     * reusable.
 +     *
 +     * @return operation builder
 +     */
 +    public TransactionOp transactionOp();
 +
 +    /**
 +     * Perform a sync on the given path - syncs are always in the background
 +     *
 +     * @param path                    the path
 +     * @param backgroundContextObject optional context
 +     * @deprecated use {@link #sync()} instead
 +     */
 +    @Deprecated
 +    public void sync(String path, Object backgroundContextObject);
 +
 +    /**
 +     * Create all nodes in the specified path as containers if they don't
 +     * already exist
 +     *
 +     * @param path path to create
 +     * @throws Exception errors
 +     */
 +    public void createContainers(String path) throws Exception;
 +
 +    /**
 +     * Start a sync builder. Note: sync is ALWAYS in the background even
 +     * if you don't use one of the background() methods
 +     *
 +     * @return builder object
 +     */
 +    public SyncBuilder sync();
 +
 +    /**
++     * Start a remove watches builder.
++     * @return builder object
++     */
++    public RemoveWatchesBuilder watches();
++
++    /**
 +     * Returns the listenable interface for the Connect State
 +     *
 +     * @return listenable
 +     */
 +    public Listenable<ConnectionStateListener> getConnectionStateListenable();
 +
 +    /**
 +     * Returns the listenable interface for events
 +     *
 +     * @return listenable
 +     */
 +    public Listenable<CuratorListener> getCuratorListenable();
 +
 +    /**
 +     * Returns the listenable interface for unhandled errors
 +     *
 +     * @return listenable
 +     */
 +    public Listenable<UnhandledErrorListener> getUnhandledErrorListenable();
 +
 +    /**
 +     * Returns a facade of the current instance that does _not_ automatically
 +     * pre-pend the namespace to all paths
 +     *
 +     * @return facade
 +     * @deprecated Since 2.9.0 - use {@link #usingNamespace} passing <code>null</code>
 +     */
 +    @Deprecated
 +    public CuratorFramework nonNamespaceView();
 +
 +    /**
 +     * Returns a facade of the current instance that uses the specified namespace
 +     * or no namespace if <code>newNamespace</code> is <code>null</code>.
 +     *
 +     * @param newNamespace the new namespace or null for none
 +     * @return facade
 +     */
 +    public CuratorFramework usingNamespace(String newNamespace);
 +
 +    /**
 +     * Return the current namespace or "" if none
 +     *
 +     * @return namespace
 +     */
 +    public String getNamespace();
 +
 +    /**
 +     * Return the managed zookeeper client
 +     *
 +     * @return client
 +     */
 +    public CuratorZookeeperClient getZookeeperClient();
 +
 +    /**
 +     * Allocates an ensure path instance that is namespace aware
 +     *
 +     * @param path path to ensure
 +     * @return new EnsurePath instance
 +     * @deprecated Since 2.9.0 - prefer {@link CreateBuilder#creatingParentContainersIfNeeded()}, {@link ExistsBuilder#creatingParentContainersIfNeeded()}
 +     * or {@link CuratorFramework#createContainers(String)}
 +     */
 +    @Deprecated
 +    public EnsurePath newNamespaceAwareEnsurePath(String path);
 +
 +    /**
 +     * Curator can hold internal references to watchers that may inhibit garbage collection.
 +     * Call this method on watchers you are no longer interested in.
 +     *
 +     * @param watcher the watcher
++     * 
++     * @deprecated As of ZooKeeper 3.5 Curators recipes will handle removing watcher references
++     * when they are no longer used.
 +     */
++    @Deprecated
 +    public void clearWatcherReferences(Watcher watcher);
 +        
 +    /**
 +     * Block until a connection to ZooKeeper is available or the maxWaitTime has been exceeded
 +     * @param maxWaitTime The maximum wait time. Specify a value &lt;= 0 to wait indefinitely
 +     * @param units The time units for the maximum wait time.
 +     * @return True if connection has been established, false otherwise.
 +     * @throws InterruptedException If interrupted while waiting
 +     */
 +    public boolean blockUntilConnected(int maxWaitTime, TimeUnit units) throws InterruptedException;
 +    
 +    /**
 +     * Block until a connection to ZooKeeper is available. This method will not return until a
 +     * connection is available or it is interrupted, in which case an InterruptedException will
 +     * be thrown
 +     * @throws InterruptedException If interrupted while waiting
 +     */
 +    public void blockUntilConnected() throws InterruptedException;
++
++    /**
++     * Returns a facade of the current instance that tracks
++     * watchers created and allows a one-shot removal of all watchers
++     * via {@link WatcherRemoveCuratorFramework#removeWatchers()}
++     *
++     * @return facade
++     */
++    public WatcherRemoveCuratorFramework newWatcherRemoveCuratorFramework();
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java
index 5a2dc56,480d5ec..5dea211
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java
@@@ -1,95 -1,85 +1,100 @@@
 -/**
 - * 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.curator.framework.api;
 -
 -import org.apache.curator.framework.CuratorFramework;
 -import org.apache.zookeeper.Watcher;
 -
 -public enum CuratorEventType
 -{
 -    /**
 -     * Corresponds to {@link CuratorFramework#create()}
 -     */
 -    CREATE,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#delete()}
 -     */
 -    DELETE,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#checkExists()}
 -     */
 -    EXISTS,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#getData()}
 -     */
 -    GET_DATA,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#setData()}
 -     */
 -    SET_DATA,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#getChildren()}
 -     */
 -    CHILDREN,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#sync(String, Object)}
 -     */
 -    SYNC,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#getACL()}
 -     */
 -    GET_ACL,
 -
 -    /**
 -     * Corresponds to {@link CuratorFramework#setACL()}
 -     */
 -    SET_ACL,
 -
 -    /**
 -     * Corresponds to {@link Watchable#usingWatcher(Watcher)} or {@link Watchable#watched()}
 -     */
 -    WATCHED,
 -    
 -    /**
 -     * Corresponds to {@link CuratorFramework#removeWatches()}
 -     */
 -    REMOVE_WATCHES,
 -
 -    /**
 -     * Event sent when client is being closed
 -     */
 -    CLOSING
 -}
 +/**
 + * 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.curator.framework.api;
 +
 +import org.apache.curator.framework.CuratorFramework;
 +import org.apache.zookeeper.Watcher;
 +
 +public enum CuratorEventType
 +{
 +    /**
 +     * Corresponds to {@link CuratorFramework#create()}
 +     */
 +    CREATE,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#delete()}
 +     */
 +    DELETE,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#checkExists()}
 +     */
 +    EXISTS,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#getData()}
 +     */
 +    GET_DATA,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#setData()}
 +     */
 +    SET_DATA,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#getChildren()}
 +     */
 +    CHILDREN,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#sync(String, Object)}
 +     */
 +    SYNC,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#getACL()}
 +     */
 +    GET_ACL,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#setACL()}
 +     */
 +    SET_ACL,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#transaction()}
 +     */
 +    TRANSACTION,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#getConfig()}
 +     */
 +    GET_CONFIG,
 +
 +    /**
 +     * Corresponds to {@link CuratorFramework#reconfig()}
 +     */
 +    RECONFIG,
 +
 +    /**
 +     * Corresponds to {@link Watchable#usingWatcher(Watcher)} or {@link Watchable#watched()}
 +     */
 +    WATCHED,
 +
 +    /**
++     * Corresponds to {@link CuratorFramework#watches()} ()}
++     */
++    REMOVE_WATCHES,
++
++    /**
 +     * Event sent when client is being closed
 +     */
 +    CLOSING
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
index 900374b,b078768..41bb7cd
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
@@@ -27,13 -27,11 +27,14 @@@ import org.apache.curator.CuratorConnec
  import org.apache.curator.CuratorZookeeperClient;
  import org.apache.curator.RetryLoop;
  import org.apache.curator.TimeTrace;
 +import org.apache.curator.framework.AuthInfo;
  import org.apache.curator.framework.CuratorFramework;
  import org.apache.curator.framework.CuratorFrameworkFactory;
+ import org.apache.curator.framework.WatcherRemoveCuratorFramework;
  import org.apache.curator.framework.api.*;
 +import org.apache.curator.framework.api.transaction.CuratorMultiTransaction;
  import org.apache.curator.framework.api.transaction.CuratorTransaction;
 +import org.apache.curator.framework.api.transaction.TransactionOp;
  import org.apache.curator.framework.listen.Listenable;
  import org.apache.curator.framework.listen.ListenerContainer;
  import org.apache.curator.framework.state.ConnectionState;
@@@ -73,9 -70,10 +74,10 @@@ public class CuratorFrameworkImpl imple
      private final BlockingQueue<OperationAndData<?>> backgroundOperations;
      private final NamespaceImpl namespace;
      private final ConnectionStateManager connectionStateManager;
 -    private final AtomicReference<AuthInfo> authInfo = new AtomicReference<AuthInfo>();
 +    private final List<AuthInfo> authInfos;
      private final byte[] defaultData;
      private final FailedDeleteManager failedDeleteManager;
+     private final FailedRemoveWatchManager failedRemoveWatcherManager;
      private final CompressionProvider compressionProvider;
      private final ACLProvider aclProvider;
      private final NamespaceFacadeCache namespaceFacadeCache;
@@@ -125,22 -142,23 +127,29 @@@
  
          byte[] builderDefaultData = builder.getDefaultData();
          defaultData = (builderDefaultData != null) ? Arrays.copyOf(builderDefaultData, builderDefaultData.length) : new byte[0];
 -
 -        if ( builder.getAuthScheme() != null )
 -        {
 -            authInfo.set(new AuthInfo(builder.getAuthScheme(), builder.getAuthValue()));
 -        }
 +        authInfos = buildAuths(builder);
  
          failedDeleteManager = new FailedDeleteManager(this);
+         failedRemoveWatcherManager = new FailedRemoveWatchManager(this);
          namespaceFacadeCache = new NamespaceFacadeCache(this);
      }
  
 +    private List<AuthInfo> buildAuths(CuratorFrameworkFactory.Builder builder)
 +    {
 +        ImmutableList.Builder<AuthInfo> builder1 = ImmutableList.builder();
 +        if ( builder.getAuthInfos() != null )
 +        {
 +            builder1.addAll(builder.getAuthInfos());
 +        }
 +        return builder1.build();
 +    }
 +
+     @Override
+     public WatcherRemoveCuratorFramework newWatcherRemoveCuratorFramework()
+     {
+         return new WatcherRemovalFacade(this);
+     }
+ 
      private ZookeeperFactory makeZookeeperFactory(final ZookeeperFactory actualZookeeperFactory)
      {
          return new ZookeeperFactory()
@@@ -478,7 -463,13 +488,13 @@@
      {
          return new SyncBuilderImpl(this);
      }
 -    
 +
+     @Override
+     public RemoveWatchesBuilder watches()
+     {
+         return new RemoveWatchesBuilderImpl(this);
+     }
+ 
      protected void internalSync(CuratorFrameworkImpl impl, String path, Object context)
      {
          BackgroundOperation<String> operation = new BackgroundSyncImpl(impl, context);
@@@ -506,7 -497,12 +522,12 @@@
      {
          return failedDeleteManager;
      }
 -    
 +
+     FailedRemoveWatchManager getFailedRemoveWatcherManager()
+     {
+         return failedRemoveWatcherManager;
 -    }    
++    }
+ 
      RetryLoop newRetryLoop()
      {
          return client.newRetryLoop();

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
index 51641b8,51691dd..2a98f56
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
@@@ -259,9 -251,9 +259,9 @@@ class DeleteBuilderImpl implements Dele
          catch ( Exception e )
          {
              //Only retry a guaranteed delete if it's a retryable error
 -            if( RetryLoop.isRetryException(e) && guaranteed )
 +            if( (RetryLoop.isRetryException(e) || (e instanceof InterruptedException)) && guaranteed )
              {
-                 client.getFailedDeleteManager().addFailedDelete(unfixedPath);
+                 client.getFailedDeleteManager().addFailedOperation(unfixedPath);
              }
              throw e;
          }

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
----------------------------------------------------------------------
diff --cc curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
index a837809,0000000..5468bd4
mode 100644,000000..100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java
@@@ -1,187 -1,0 +1,188 @@@
 +/**
 + * 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.curator.framework.imps;
 +
 +import org.apache.curator.RetryLoop;
 +import org.apache.curator.TimeTrace;
 +import org.apache.curator.framework.api.BackgroundCallback;
 +import org.apache.curator.framework.api.BackgroundStatable;
 +import org.apache.curator.framework.api.CuratorEvent;
 +import org.apache.curator.framework.api.CuratorEventType;
 +import org.apache.curator.framework.api.CuratorWatcher;
 +import org.apache.curator.framework.api.Ensembleable;
 +import org.apache.curator.framework.api.GetConfigBuilder;
 +import org.apache.zookeeper.AsyncCallback;
 +import org.apache.zookeeper.Watcher;
++import org.apache.zookeeper.ZooDefs;
 +import org.apache.zookeeper.data.Stat;
 +import java.util.concurrent.Callable;
 +import java.util.concurrent.Executor;
 +
 +public class GetConfigBuilderImpl implements GetConfigBuilder, BackgroundOperation<Void>
 +{
 +    private final CuratorFrameworkImpl client;
 +
 +    private Backgrounding backgrounding;
 +    private Watching watching;
 +    private Stat stat;
 +
 +    public GetConfigBuilderImpl(CuratorFrameworkImpl client)
 +    {
 +        this.client = client;
 +        backgrounding = new Backgrounding();
 +        watching = new Watching();
 +    }
 +
 +    @Override
 +    public Ensembleable<byte[]> storingStatIn(Stat stat)
 +    {
 +        this.stat = stat;
 +        return this;
 +    }
 +
 +    @Override
 +    public BackgroundStatable<Ensembleable<byte[]>> watched()
 +    {
 +        watching = new Watching(true);
 +        return this;
 +    }
 +
 +    @Override
 +    public GetConfigBuilder usingWatcher(Watcher watcher)
 +    {
 +        watching = new Watching(client, watcher);
 +        return this;
 +    }
 +
 +    @Override
 +    public GetConfigBuilder usingWatcher(final CuratorWatcher watcher)
 +    {
 +        watching = new Watching(client, watcher);
 +        return this;
 +    }
 +
 +    @Override
 +    public Ensembleable<byte[]> inBackground()
 +    {
 +        backgrounding = new Backgrounding(true);
 +        return this;
 +    }
 +
 +    @Override
 +    public Ensembleable<byte[]> inBackground(Object context)
 +    {
 +        backgrounding = new Backgrounding(context);
 +        return this;
 +    }
 +
 +    @Override
 +    public Ensembleable<byte[]> inBackground(BackgroundCallback callback)
 +    {
 +        backgrounding = new Backgrounding(callback);
 +        return this;
 +    }
 +
 +    @Override
 +    public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context)
 +    {
 +        backgrounding = new Backgrounding(callback, context);
 +        return this;
 +    }
 +
 +    @Override
 +    public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(callback, executor);
 +        return this;
 +    }
 +
 +    @Override
 +    public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor)
 +    {
 +        backgrounding = new Backgrounding(client, callback, context, executor);
 +        return this;
 +    }
 +
 +    @Override
 +    public byte[] forEnsemble() throws Exception
 +    {
 +        if ( backgrounding.inBackground() )
 +        {
 +            client.processBackgroundOperation(new OperationAndData<Void>(this, null, backgrounding.getCallback(), null, backgrounding.getContext()), null);
 +            return null;
 +        }
 +        else
 +        {
 +            return configInForeground();
 +        }
 +    }
 +
 +    @Override
 +    public void performBackgroundOperation(final OperationAndData<Void> operationAndData) throws Exception
 +    {
 +        final TimeTrace trace = client.getZookeeperClient().startTracer("GetDataBuilderImpl-Background");
 +        AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
 +        {
 +            @Override
 +            public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)
 +            {
 +                trace.commit();
 +                CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_CONFIG, rc, path, null, ctx, stat, data, null, null, null, null);
 +                client.processBackgroundOperation(operationAndData, event);
 +            }
 +        };
 +        if ( watching.isWatched() )
 +        {
 +            client.getZooKeeper().getConfig(true, callback, backgrounding.getContext());
 +        }
 +        else
 +        {
-             client.getZooKeeper().getConfig(watching.getWatcher(), callback, backgrounding.getContext());
++            client.getZooKeeper().getConfig(watching.getWatcher(client, ZooDefs.CONFIG_NODE), callback, backgrounding.getContext());
 +        }
 +    }
 +
 +    private byte[] configInForeground() throws Exception
 +    {
 +        TimeTrace trace = client.getZookeeperClient().startTracer("GetConfigBuilderImpl-Foreground");
 +        try
 +        {
 +            return RetryLoop.callWithRetry
 +            (
 +                client.getZookeeperClient(),
 +                new Callable<byte[]>()
 +                {
 +                    @Override
 +                    public byte[] call() throws Exception
 +                    {
 +                        if ( watching.isWatched() )
 +                        {
 +                            return client.getZooKeeper().getConfig(true, stat);
 +                        }
-                         return client.getZooKeeper().getConfig(watching.getWatcher(), stat);
++                        return client.getZooKeeper().getConfig(watching.getWatcher(client, ZooDefs.CONFIG_NODE), stat);
 +                    }
 +                }
 +            );
 +        }
 +        finally
 +        {
 +            trace.commit();
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/NodeCache.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/NodeCache.java
index 72ee5ff,4d87732..49b9a3f
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/NodeCache.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/NodeCache.java
@@@ -53,9 -55,10 +54,9 @@@ import java.util.concurrent.atomic.Atom
  public class NodeCache implements Closeable
  {
      private final Logger log = LoggerFactory.getLogger(getClass());
-     private final CuratorFramework client;
+     private final WatcherRemoveCuratorFramework client;
      private final String path;
      private final boolean dataIsCompressed;
 -    private final EnsurePath ensurePath;
      private final AtomicReference<ChildData> data = new AtomicReference<ChildData>(null);
      private final AtomicReference<State> state = new AtomicReference<State>(State.LATENT);
      private final ListenerContainer<NodeCacheListener> listeners = new ListenerContainer<NodeCacheListener>();
@@@ -127,9 -130,10 +128,9 @@@
       */
      public NodeCache(CuratorFramework client, String path, boolean dataIsCompressed)
      {
-         this.client = client;
+         this.client = client.newWatcherRemoveCuratorFramework();
          this.path = PathUtils.validatePath(path);
          this.dataIsCompressed = dataIsCompressed;
 -        ensurePath = client.newNamespaceAwareEnsurePath(path).excludingLast();
      }
  
      /**

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java
index b5d912c,5c413b6..99a652d
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java
@@@ -42,16 -44,16 +43,13 @@@ import org.apache.zookeeper.Watcher
  import org.apache.zookeeper.data.Stat;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
++
  import java.io.Closeable;
  import java.io.IOException;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
--import java.util.concurrent.ConcurrentMap;
--import java.util.concurrent.Exchanger;
--import java.util.concurrent.ExecutorService;
--import java.util.concurrent.Executors;
--import java.util.concurrent.ThreadFactory;
++import java.util.concurrent.*;
  import java.util.concurrent.atomic.AtomicReference;
  
  /**

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
index 4f3ffb6,c3958aa..bda00bf
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
@@@ -524,13 -510,11 +525,13 @@@ public class TreeCache implements Close
       * @param cacheData        if true, node contents are cached in addition to the stat
       * @param dataIsCompressed if true, data in the path is compressed
       * @param executorService  Closeable ExecutorService to use for the TreeCache's background thread
 +     * @param createParentNodes true to create parent nodes as containers
       */
 -    TreeCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, int maxDepth, final CloseableExecutorService executorService)
 +    TreeCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, int maxDepth, final CloseableExecutorService executorService, boolean createParentNodes)
      {
 +        this.createParentNodes = createParentNodes;
          this.root = new TreeNode(validatePath(path), null);
-         this.client = client;
+         this.client = client.newWatcherRemoveCuratorFramework();
          this.cacheData = cacheData;
          this.dataIsCompressed = dataIsCompressed;
          this.maxDepth = maxDepth;

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/main/java/org/apache/curator/framework/recipes/leader/LeaderLatch.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessSemaphoreV2.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessSemaphoreV2.java
index f4af39b,2a55107..3bf2ec3
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessSemaphoreV2.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessSemaphoreV2.java
@@@ -21,16 -21,15 +21,17 @@@ package org.apache.curator.framework.re
  
  import com.google.common.base.Preconditions;
  import com.google.common.collect.ImmutableList;
 -import org.apache.curator.framework.WatcherRemoveCuratorFramework;
 -import org.apache.curator.utils.CloseableUtils;
 +import com.google.common.collect.Sets;
- 
- import org.apache.curator.utils.CloseableUtils;
  import org.apache.curator.RetryLoop;
  import org.apache.curator.framework.CuratorFramework;
++import org.apache.curator.framework.WatcherRemoveCuratorFramework;
  import org.apache.curator.framework.api.PathAndBytesable;
  import org.apache.curator.framework.imps.CuratorFrameworkState;
  import org.apache.curator.framework.recipes.shared.SharedCountListener;
  import org.apache.curator.framework.recipes.shared.SharedCountReader;
  import org.apache.curator.framework.state.ConnectionState;
++import org.apache.curator.utils.CloseableUtils;
++import org.apache.curator.utils.PathUtils;
  import org.apache.curator.utils.ZKPaths;
  import org.apache.zookeeper.CreateMode;
  import org.apache.zookeeper.KeeperException;
@@@ -38,13 -37,12 +39,13 @@@ import org.apache.zookeeper.WatchedEven
  import org.apache.zookeeper.Watcher;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
++
  import java.io.IOException;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.List;
 +import java.util.Set;
  import java.util.concurrent.TimeUnit;
--import org.apache.curator.utils.PathUtils;
  
  /**
   * <p>

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
index 0d963e0,98b09c9..0b482ef
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
@@@ -20,8 -20,8 +20,9 @@@
  package org.apache.curator.framework.recipes.nodes;
  
  import com.google.common.base.Preconditions;
 +
  import org.apache.curator.framework.CuratorFramework;
+ import org.apache.curator.framework.WatcherRemoveCuratorFramework;
  import org.apache.curator.framework.api.ACLBackgroundPathAndBytesable;
  import org.apache.curator.framework.api.BackgroundCallback;
  import org.apache.curator.framework.api.CreateModable;
@@@ -210,12 -189,12 +211,12 @@@ public class PersistentEphemeralNode im
       * @param basePath the base path for the node
       * @param data     data for the node
       */
 -    public PersistentEphemeralNode(CuratorFramework client, Mode mode, String basePath, byte[] data)
 +    public PersistentEphemeralNode(CuratorFramework client, Mode mode, String basePath, byte[] initData)
      {
-         this.client = Preconditions.checkNotNull(client, "client cannot be null");
+         this.client = Preconditions.checkNotNull(client, "client cannot be null").newWatcherRemoveCuratorFramework();
          this.basePath = PathUtils.validatePath(basePath);
          this.mode = Preconditions.checkNotNull(mode, "mode cannot be null");
 -        data = Preconditions.checkNotNull(data, "data cannot be null");
 +        final byte[] data = Preconditions.checkNotNull(initData, "data cannot be null");
  
          backgroundCallback = new BackgroundCallback()
          {

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/main/java/org/apache/curator/framework/recipes/shared/SharedValue.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
index 14d061f,ffcf251..3571ca7
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
@@@ -28,10 -28,9 +28,10 @@@ import org.apache.curator.framework.api
  import org.apache.curator.framework.api.CuratorEvent;
  import org.apache.curator.framework.api.Pathable;
  import org.apache.curator.framework.api.UnhandledErrorListener;
- import org.apache.curator.framework.imps.CuratorFrameworkImpl;
+ import org.apache.curator.framework.imps.TestCleanState;
  import org.apache.curator.retry.RetryOneTime;
  import org.apache.curator.test.BaseClassForTests;
 +import org.apache.curator.test.ExecuteCalledWatchingExecutorService;
  import org.apache.curator.test.KillSession;
  import org.apache.curator.test.Timing;
  import org.apache.curator.utils.CloseableUtils;
@@@ -957,9 -1041,133 +966,10 @@@ public class TestPathChildrenCache exte
              latch.await(5, TimeUnit.SECONDS);
  
              Assert.assertTrue(latch.getCount() == 1, "Unexpected exception occurred");
-         } finally
+         }
+         finally
          {
-             CloseableUtils.closeQuietly(client);
+             TestCleanState.closeAndTestClean(client);
          }
      }
 -
 -    public static class ExecuteCalledWatchingExecutorService extends DelegatingExecutorService
 -    {
 -        boolean executeCalled = false;
 -
 -        public ExecuteCalledWatchingExecutorService(ExecutorService delegate)
 -        {
 -            super(delegate);
 -        }
 -
 -        @Override
 -        public synchronized void execute(Runnable command)
 -        {
 -            executeCalled = true;
 -            super.execute(command);
 -        }
 -
 -        public synchronized boolean isExecuteCalled()
 -        {
 -            return executeCalled;
 -        }
 -
 -        public synchronized void setExecuteCalled(boolean executeCalled)
 -        {
 -            this.executeCalled = executeCalled;
 -        }
 -    }
 -
 -    public static class DelegatingExecutorService implements ExecutorService
 -    {
 -        private final ExecutorService delegate;
 -
 -        public DelegatingExecutorService(
 -                ExecutorService delegate
 -        )
 -        {
 -            this.delegate = delegate;
 -        }
 -
 -
 -        @Override
 -        public void shutdown()
 -        {
 -            delegate.shutdown();
 -        }
 -
 -        @Override
 -        public List<Runnable> shutdownNow()
 -        {
 -            return delegate.shutdownNow();
 -        }
 -
 -        @Override
 -        public boolean isShutdown()
 -        {
 -            return delegate.isShutdown();
 -        }
 -
 -        @Override
 -        public boolean isTerminated()
 -        {
 -            return delegate.isTerminated();
 -        }
 -
 -        @Override
 -        public boolean awaitTermination(long timeout, TimeUnit unit)
 -                throws InterruptedException
 -        {
 -            return delegate.awaitTermination(timeout, unit);
 -        }
 -
 -        @Override
 -        public <T> Future<T> submit(Callable<T> task)
 -        {
 -            return delegate.submit(task);
 -        }
 -
 -        @Override
 -        public <T> Future<T> submit(Runnable task, T result)
 -        {
 -            return delegate.submit(task, result);
 -        }
 -
 -        @Override
 -        public Future<?> submit(Runnable task)
 -        {
 -            return delegate.submit(task);
 -        }
 -
 -        @Override
 -        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
 -                throws InterruptedException
 -        {
 -            return delegate.invokeAll(tasks);
 -        }
 -
 -        @Override
 -        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
 -                throws InterruptedException
 -        {
 -            return delegate.invokeAll(tasks, timeout, unit);
 -        }
 -
 -        @Override
 -        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
 -                throws InterruptedException, ExecutionException
 -        {
 -            return delegate.invokeAny(tasks);
 -        }
 -
 -        @Override
 -        public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
 -                throws InterruptedException, ExecutionException, TimeoutException
 -        {
 -            return delegate.invokeAny(tasks, timeout, unit);
 -        }
 -
 -        @Override
 -        public void execute(Runnable command)
 -        {
 -            delegate.execute(command);
 -        }
 -    }
  }

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMultiMutex.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutex.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
index 99ea11f,49e5d19..f44d238
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
@@@ -27,11 -28,7 +28,10 @@@ import org.apache.curator.framework.sta
  import org.apache.curator.retry.ExponentialBackoffRetry;
  import org.apache.curator.test.BaseClassForTests;
  import org.apache.curator.test.KillSession;
- import org.apache.curator.test.TestingServer;
  import org.apache.curator.test.Timing;
 +import org.apache.curator.utils.CloseableUtils;
 +import org.apache.curator.utils.ZKPaths;
 +import org.apache.zookeeper.CreateMode;
  import org.testng.Assert;
  import org.testng.annotations.Test;
  import java.util.List;

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessSemaphore.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessSemaphore.java
index 631b7c7,2797b5f..3ba75d8
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessSemaphore.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessSemaphore.java
@@@ -528,47 -531,7 +531,47 @@@ public class TestInterProcessSemaphore 
              {
                  CloseableUtils.closeQuietly(l);
              }
-             CloseableUtils.closeQuietly(client);
+             TestCleanState.closeAndTestClean(client);
          }
      }
 +
 +    @Test
 +    public void testChildReaperCleansUpLockNodes() throws Exception
 +    {
 +        Timing timing = new Timing();
 +        CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
 +        client.start();
 +
 +        ChildReaper childReaper = null;
 +        try
 +        {
 +            InterProcessSemaphoreV2 semaphore = new InterProcessSemaphoreV2(client, "/test/lock", 1);
 +            semaphore.returnLease(semaphore.acquire(timing.forWaiting().seconds(), TimeUnit.SECONDS));
 +
 +            Assert.assertTrue(client.getChildren().forPath("/test").size() > 0);
 +
 +            childReaper = new ChildReaper(
 +                    client,
 +                    "/test",
 +                    Reaper.Mode.REAP_UNTIL_GONE,
 +                    ChildReaper.newExecutorService(),
 +                    1,
 +                    "/test-leader",
 +                    InterProcessSemaphoreV2.LOCK_SCHEMA
 +            );
 +            childReaper.start();
 +
 +            timing.forWaiting().sleepABit();
 +
 +            List<String> children = client.getChildren().forPath("/test");
 +
 +            Assert.assertEquals(children.size(), 0, "All children of /test should have been reaped");
 +        }
 +        finally
 +        {
 +            CloseableUtils.closeQuietly(childReaper);
 +            CloseableUtils.closeQuietly(client);
 +        }
 +
 +    }
  }

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
index 9f5907a,5a58b2a..c81cc65
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
@@@ -20,17 -20,15 +20,16 @@@ package org.apache.curator.framework.re
  
  import com.google.common.base.Throwables;
  import com.google.common.collect.Lists;
- 
  import org.apache.curator.framework.CuratorFramework;
  import org.apache.curator.framework.CuratorFrameworkFactory;
 +import org.apache.curator.framework.api.BackgroundCallback;
 +import org.apache.curator.framework.api.CuratorEvent;
+ import org.apache.curator.framework.imps.TestCleanState;
  import org.apache.curator.framework.state.ConnectionState;
  import org.apache.curator.framework.state.ConnectionStateListener;
  import org.apache.curator.retry.RetryOneTime;
  import org.apache.curator.test.BaseClassForTests;
  import org.apache.curator.test.KillSession;
--import org.apache.curator.test.TestingServer;
  import org.apache.curator.test.Timing;
  import org.apache.curator.utils.CloseableUtils;
  import org.apache.curator.utils.ZKPaths;
@@@ -129,9 -123,10 +127,10 @@@ public class TestPersistentEphemeralNod
      @Test
      public void testNoServerAtStart() throws Exception
      {
 -        server.close();
 +        server.stop();
  
          CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
+         PersistentEphemeralNode node = null;
          try
          {
              client.start();

http://git-wip-us.apache.org/repos/asf/curator/blob/d5d12c88/curator-test/src/main/java/org/apache/curator/test/BaseClassForTests.java
----------------------------------------------------------------------
diff --cc curator-test/src/main/java/org/apache/curator/test/BaseClassForTests.java
index 13c3138,d5c434f..6ef3bb0
--- a/curator-test/src/main/java/org/apache/curator/test/BaseClassForTests.java
+++ b/curator-test/src/main/java/org/apache/curator/test/BaseClassForTests.java
@@@ -35,11 -34,10 +35,12 @@@ public class BaseClassForTest
  
      private static final int    RETRY_WAIT_MS = 5000;
      private static final String INTERNAL_PROPERTY_DONT_LOG_CONNECTION_ISSUES;
+     private static final String INTERNAL_PROPERTY_REMOVE_WATCHERS_IN_FOREGROUND;
 +    private static final String INTERNAL_RETRY_FAILED_TESTS;
      static
      {
 -        String s = null;
 +        String logConnectionIssues = null;
 +        String retryFailedTests = null;
          try
          {
              // use reflection to avoid adding a circular dependency in the pom
@@@ -51,8 -47,18 +52,19 @@@
          {
              e.printStackTrace();
          }
 -        INTERNAL_PROPERTY_DONT_LOG_CONNECTION_ISSUES = s;
 -
 +        INTERNAL_PROPERTY_DONT_LOG_CONNECTION_ISSUES = logConnectionIssues;
 +        INTERNAL_RETRY_FAILED_TESTS = retryFailedTests;
++        String s = null;
+         try
+         {
+             // use reflection to avoid adding a circular dependency in the pom
+             s = (String)Class.forName("org.apache.curator.utils.DebugUtils").getField("PROPERTY_REMOVE_WATCHERS_IN_FOREGROUND").get(null);
+         }
+         catch ( Exception e )
+         {
+             e.printStackTrace();
+         }
+         INTERNAL_PROPERTY_REMOVE_WATCHERS_IN_FOREGROUND = s;
      }
  
      @BeforeSuite(alwaysRun = true)
@@@ -89,18 -96,9 +102,19 @@@
      @AfterMethod
      public void teardown() throws Exception
      {
+         System.clearProperty(INTERNAL_PROPERTY_REMOVE_WATCHERS_IN_FOREGROUND);
 -        server.close();
 -        server = null;
 +        if ( server != null )
 +        {
 +            try
 +            {
 +                server.close();
 +            }
 +            catch ( IOException e )
 +            {
 +                e.printStackTrace();
 +            }
 +            server = null;
 +        }
      }
  
      private static class RetryTest implements IRetryAnalyzer