
co.cask.common.security.zookeeper.ZKExtOperations Maven / Gradle / Ivy
/*
* Copyright © 2014 Cask Data, Inc.
*
* Licensed 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 co.cask.common.security.zookeeper;
import co.cask.common.io.AsyncFunctions;
import co.cask.common.io.Codec;
import com.google.common.base.Function;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import org.apache.twill.common.Threads;
import org.apache.twill.zookeeper.NodeData;
import org.apache.twill.zookeeper.OperationFuture;
import org.apache.twill.zookeeper.ZKClient;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
/**
* Collection of common zk operations.
*
* NOTE: When this class is matured, we could move this into twill ZKOperations.
*/
public final class ZKExtOperations {
/**
* Attempts to create a persistent node with the given content. If creation failed because the node already
* exists ({@link KeeperException.NodeExistsException}), the node will be set with the given content.
* This method is suitable for cases where the node expected to be non-existed.
*
* @param zkClient The ZKClient to perform the operations.
* @param path The path in ZK.
* @param data The content of the ZK node.
* @param result The result that will be set into the result future when completed successfully.
* @param maxFailure Maximum number of times to try to create/set the content.
* @param Type of the result.
* @return A {@link ListenableFuture} that will be completed when node is created or data is set. The future will
* fail if failed to create and to set the data. Calling {@link ListenableFuture#cancel(boolean)} has
* no effect.
*/
public static ListenableFuture createOrSet(ZKClient zkClient, String path,
byte[] data, V result, int maxFailure) {
return setContent(zkClient, path, data, result, maxFailure, true, null);
}
/**
* Attempts to create a persistent node with the given content. If creation failed because the node already
* exists ({@link KeeperException.NodeExistsException}), the node will be set with the given content.
* This method is suitable for cases where the node expected to be non-existed.
*
* @param zkClient The ZKClient to perform the operations.
* @param path The path in ZK.
* @param data The content of the ZK node.
* @param result The result that will be set into the result future when completed successfully.
* @param maxFailure Maximum number of times to try to create/set the content.
* @param createAcl The access control list to set on the node, if it is created.
* @param Type of the result.
* @return A {@link ListenableFuture} that will be completed when node is created or data is set. The future will
* fail if failed to create and to set the data. Calling {@link ListenableFuture#cancel(boolean)} has
* no effect.
*/
public static ListenableFuture createOrSet(ZKClient zkClient, String path,
byte[] data, V result, int maxFailure, List createAcl) {
return setContent(zkClient, path, data, result, maxFailure, true, createAcl);
}
/**
* Attempts to set the content of the given node. If it failed due to node not exists
* ({@link KeeperException.NoNodeException}), a persistent node will be created with the given content.
* This method is suitable for cases where the node is expected to be existed.
*
* @param zkClient The ZKClient to perform the operations.
* @param path The path in ZK.
* @param data The content of the ZK node.
* @param result The result that will be set into the result future when completed successfully.
* @param maxFailure Maximum number of times to try to create/set the content.
* @param Type of the result.
* @return A {@link ListenableFuture} that will be completed when node is created or data is set. The future will
* fail if failed to create and to set the data. Calling {@link ListenableFuture#cancel(boolean)} has
* no effect.
*/
public static ListenableFuture setOrCreate(ZKClient zkClient, String path,
byte[] data, V result, int maxFailure) {
return setContent(zkClient, path, data, result, maxFailure, false, null);
}
/**
* Update the content of the given node. If the node doesn't exists, it will try to create the node. Same as calling
*
* {@link #updateOrCreate(ZKClient, String, Function, Codec, List)
* updateOrCreate(zkClient, path, modifier, codec, null)}
*
* @see #updateOrCreate(ZKClient, String, Function, Codec, List)
*/
public static ListenableFuture updateOrCreate(ZKClient zkClient, String path,
Function modifier, Codec codec) {
return updateOrCreate(zkClient, path, modifier, codec, null);
}
/**
* Update the content of the given node. If the node doesn't exists, it will try to create the node.
* The modifier will be executed in the ZooKeeper callback thread, hence no blocking operation should be performed
* in it. If blocking operation is needed, use the async version of this method.
*
* @see #updateOrCreate(ZKClient, String, AsyncFunction, Codec, List)
*/
public static ListenableFuture updateOrCreate(ZKClient zkClient, String path,
Function modifier, Codec codec,
@Nullable List createAcl) {
SettableFuture resultFuture = SettableFuture.create();
AsyncFunction asyncModifier = AsyncFunctions.asyncWrap(modifier);
getAndSet(zkClient, path, asyncModifier, codec, resultFuture, createAcl);
return resultFuture;
}
/**
* Update the content of the given node. If the node doesn't exists, it will try to create the node. Same as calling
*
* {@link #updateOrCreate(ZKClient, String, AsyncFunction, Codec, List)
* updateOrCreate(zkClient, path, modifier, codec, null)}
*
* @see #updateOrCreate(ZKClient, String, AsyncFunction, Codec, List)
*/
public static ListenableFuture updateOrCreate(ZKClient zkClient, String path,
AsyncFunction modifier, Codec codec) {
return updateOrCreate(zkClient, path, modifier, codec, null);
}
/**
* Update the content of the given node. If the node doesn't exists, it will try to create the node. If the node
* exists, the existing content of the data will be provided to the modifier function to generate new content. A
* conditional set will be performed which requires existing content the same as the one provided to the modifier
* function. If the conditional set failed, the latest content will be fetched and fed to the modifier function
* again.
* This will continue until the set is successful or the modifier gave up the update, by returning {@code null}.
*
* @param zkClient The ZKClient to perform the operations.
* @param path The path in ZK.
* @param modifier A function to generate new content
* @param codec Codec to encode/decode content to/from byte array
* @param createAcl If not {@code null}, the access control list to set on the node, if it is created.
* @param Type of the content
* @return A {@link ListenableFuture} that will be completed when node is created or data is set.
* The future will carry the actual content being set into the node. The future will
* fail if failed to create and to set the data. Calling {@link ListenableFuture#cancel(boolean)} has
* no effect.
*/
public static ListenableFuture updateOrCreate(ZKClient zkClient, String path,
AsyncFunction modifier, Codec codec,
@Nullable List createAcl) {
SettableFuture resultFuture = SettableFuture.create();
getAndSet(zkClient, path, modifier, codec, resultFuture, createAcl);
return resultFuture;
}
/**
* Attempts to set the content of the given node. If it failed due to node not exists
* ({@link KeeperException.NoNodeException}), a persistent node will be created with the given content.
* This method is suitable for cases where the node is expected to be existed.
*
* @param zkClient The ZKClient to perform the operations.
* @param path The path in ZK.
* @param data The content of the ZK node.
* @param result The result that will be set into the result future when completed successfully.
* @param maxFailure Maximum number of times to try to create/set the content.
* @param createAcl The access control list to set on the node, if it is created.
* @param Type of the result.
* @return A {@link ListenableFuture} that will be completed when node is created or data is set. The future will
* fail if failed to create and to set the data. Calling {@link ListenableFuture#cancel(boolean)} has
* no effect.
*/
public static ListenableFuture setOrCreate(ZKClient zkClient, String path,
byte[] data, V result, int maxFailure, List createAcl) {
return setContent(zkClient, path, data, result, maxFailure, false, createAcl);
}
/**
* Sets the content of a ZK node. Depends on the {@code createFirst} value,
* either {@link ZKClient#create(String, byte[], org.apache.zookeeper.CreateMode)} or
* {@link ZKClient#setData(String, byte[])} wil be called first.
*
* @param zkClient The ZKClient to perform the operations.
* @param path The path in ZK.
* @param data The content of the ZK node.
* @param result The result that will be set into the result future when completed successfully.
* @param maxFailure Maximum number of times to try to create/set the content.
* @param createFirst If true, create is called first, otherwise setData is called first.
* @param Type of the result.
* @return A {@link ListenableFuture} that will be completed when node is created or data is set. The future will
* fail if failed to create and to set the data. Calling {@link ListenableFuture#cancel(boolean)} has
* no effect.
*/
private static ListenableFuture setContent(final ZKClient zkClient, final String path,
final byte[] data, final V result,
final int maxFailure, boolean createFirst,
final List createAcls) {
final SettableFuture resultFuture = SettableFuture.create();
final AtomicInteger failureCount = new AtomicInteger(0);
OperationFuture> operationFuture;
if (createFirst) {
if (createAcls != null) {
operationFuture = zkClient.create(path, data, CreateMode.PERSISTENT, createAcls);
} else {
operationFuture = zkClient.create(path, data, CreateMode.PERSISTENT);
}
} else {
operationFuture = zkClient.setData(path, data);
}
Futures.addCallback(operationFuture, new FutureCallback
© 2015 - 2025 Weber Informatics LLC | Privacy Policy