package com.linkedin.helix.manager.zk;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.I0Itec.zkclient.DataUpdater;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.exception.ZkBadVersionException;
import org.I0Itec.zkclient.exception.ZkException;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.DataTree;
import com.linkedin.helix.AccessOption;
import com.linkedin.helix.BaseDataAccessor;
import com.linkedin.helix.ZNRecord;
import com.linkedin.helix.manager.zk.ZkAsyncCallbacks.CreateCallbackHandler;
import com.linkedin.helix.manager.zk.ZkAsyncCallbacks.DeleteCallbackHandler;
import com.linkedin.helix.manager.zk.ZkAsyncCallbacks.ExistsCallbackHandler;
import com.linkedin.helix.manager.zk.ZkAsyncCallbacks.GetDataCallbackHandler;
import com.linkedin.helix.manager.zk.ZkAsyncCallbacks.SetDataCallbackHandler;
import com.linkedin.helix.store.zk.ZNode;
public class ZkBaseDataAccessor<T> implements BaseDataAccessor<T>
{
enum RetCode
{
OK, NODE_EXISTS, ERROR
}
private static Logger LOG = Logger.getLogger(ZkBaseDataAccessor.class);
private final ZkClient _zkClient;
public ZkBaseDataAccessor(ZkClient zkClient)
{
_zkClient = zkClient;
}
/**
* sync create
*/
@Override
public boolean create(String path, T record, int options)
{
return create(path, record, null, options) == RetCode.OK;
}
/**
* sync create
*/
public RetCode create(String path, T record, List<String> pathCreated, int options)
{
CreateMode mode = AccessOption.getMode(options);
if (mode == null)
{
LOG.error("Invalid create mode. options: " + options);
return RetCode.ERROR;
}
boolean retry;
do
{
retry = false;
try
{
_zkClient.create(path, record, mode);
if (pathCreated != null)
pathCreated.add(path);
return RetCode.OK;
}
catch (ZkNoNodeException e)
{
// this will happen if parent node does not exist
String parentPath = new File(path).getParent();
try
{
RetCode rc = create(parentPath, null, pathCreated, AccessOption.PERSISTENT);
if (rc == RetCode.OK || rc == RetCode.NODE_EXISTS)
{
// if parent node created/exists, retry
retry = true;
}
}
catch (Exception e1)
{
LOG.error("Exception while creating path: " + parentPath, e1);
return RetCode.ERROR;
}
}
catch (ZkNodeExistsException e)
{
LOG.warn("Node already exists. path: " + path);
return RetCode.NODE_EXISTS;
}
catch (Exception e)
{
LOG.error("Exception while creating path: " + path, e);
return RetCode.ERROR;
}
}
while (retry);
return RetCode.OK;
}
/**
* sync set
*/
@Override
public boolean set(String path, T record, int options)
{
return set(path, record, null, null, -1, options);
}
/**
* sync set
*
* @param setstat
* : if node is created instead of set, stat will NOT be set
*/
public boolean set(String path,
T record,
List<String> pathsCreated,
Stat setstat,
int expectVersion,
int options)
{
CreateMode mode = AccessOption.getMode(options);
if (mode == null)
{
LOG.error("Invalid set mode. options: " + options);
return false;
}
boolean retry;
do
{
retry = false;
try
{
// _zkClient.writeData(path, record);
Stat setStat = _zkClient.writeDataGetStat(path, record, expectVersion);
if (setstat != null)
DataTree.copyStat(setStat, setstat);
}
catch (ZkNoNodeException e)
{
// node not exists, try create. in this case, stat will not be set
try
{
RetCode rc = create(path, record, pathsCreated, options);
// if (rc == RetCode.OK || rc == RetCode.NODE_EXISTS)
// retry = true;
switch (rc)
{
case OK:
// not set stat if node is created (instead of set)
break;
case NODE_EXISTS:
retry = true;
break;
default:
LOG.error("Fail to set path by creating: " + path);
return false;
}
}
catch (Exception e1)
{
LOG.error("Exception while setting path by creating: " + path, e);
return false;
}
}
catch (ZkBadVersionException e)
{
throw e;
}
catch (Exception e)
{
LOG.error("Exception while setting path: " + path, e);
return false;
}
}
while (retry);
return true;
}
/**
* sync update
*/
@Override
public boolean update(String path, DataUpdater<T> updater, int options)
{
return update(path, updater, null, null, options) != null;
}
/**
* sync update
*
* @return: updatedData on success, or null on fail
*/
public T update(String path,
DataUpdater<T> updater,
List<String> createPaths,
Stat stat,
int options)
{
CreateMode mode = AccessOption.getMode(options);
if (mode == null)
{
LOG.error("Invalid update mode. options: " + options);
return null;
}
boolean retry;
T updatedData = null;
do
{
retry = false;
try
{
Stat readStat = new Stat();
T oldData = (T) _zkClient.readData(path, readStat);
T newData = updater.update(oldData);
Stat setStat = _zkClient.writeDataGetStat(path, newData, readStat.getVersion());
if (stat != null)
{
DataTree.copyStat(setStat, stat);
}
updatedData = newData;
}
catch (ZkBadVersionException e)
{
retry = true;
}
catch (ZkNoNodeException e)
{
// node not exist, try create
try
{
T newData = updater.update(null);
RetCode rc = create(path, newData, createPaths, options);
switch (rc)
{
case OK:
updatedData = newData;
break;
case NODE_EXISTS:
retry = true;
break;
default:
LOG.error("Fail to update path by creating: " + path);
return null;
}
}
catch (Exception e1)
{
LOG.error("Exception while updating path by creating: " + path, e1);
return null;
}
}
catch (Exception e)
{
LOG.error("Exception while updating path: " + path, e);
return null;
}
}
while (retry);
return updatedData;
}
/**
* sync get
*
*/
@Override
public T get(String path, Stat stat, int options)
{
T data = null;
try
{
data = (T) _zkClient.readData(path, stat);
}
catch (ZkNoNodeException e)
{
if (AccessOption.isThrowExceptionIfNotExist(options))
{
throw e;
}
}
return data;
}
/**
* async get
*
*/
@Override
public List<T> get(List<String> paths, List<Stat> stats, int options)
{
boolean[] needRead = new boolean[paths.size()];
Arrays.fill(needRead, true);
return get(paths, stats, needRead);
}
/**
* async get
*/
List<T> get(List<String> paths, List<Stat> stats, boolean[] needRead)
{
if (paths == null || paths.size() == 0)
{
return Collections.emptyList();
}
// init stats
if (stats != null)
{
stats.clear();
stats.addAll(Collections.<Stat> nCopies(paths.size(), null));
}
long startT = System.nanoTime();
try
{
// issue asyn get requests
GetDataCallbackHandler[] cbList = new GetDataCallbackHandler[paths.size()];
for (int i = 0; i < paths.size(); i++)
{
if (!needRead[i])
continue;
String path = paths.get(i);
cbList[i] = new GetDataCallbackHandler();
_zkClient.asyncGetData(path, cbList[i]);
}
// wait for completion
for (int i = 0; i < cbList.length; i++)
{
if (!needRead[i])
continue;
GetDataCallbackHandler cb = cbList[i];
cb.waitForSuccess();
}
// construct return results
List<T> records = new ArrayList<T>(Collections.<T> nCopies(paths.size(), null));
for (int i = 0; i < paths.size(); i++)
{
if (!needRead[i])
continue;
GetDataCallbackHandler cb = cbList[i];
if (Code.get(cb.getRc()) == Code.OK)
{
@SuppressWarnings("unchecked")
T record = (T) _zkClient.deserialize(cb._data, paths.get(i));
records.set(i, record);
if (stats != null)
{
stats.set(i, cb._stat);
}
}
}
return records;
}
finally
{
long endT = System.nanoTime();
if (LOG.isDebugEnabled())
{
LOG.debug("getData_async, size: " + paths.size() + ", paths: " + paths.get(0)
+ ",... time: " + (endT - startT) + " ns");
}
}
}
/**
* asyn getChildren
*
*/
@Override
public List<T> getChildren(String parentPath, List<Stat> stats, int options)
{
try
{
// prepare child paths
List<String> childNames = getChildNames(parentPath, options);
if (childNames == null || childNames.size() == 0)
{
return Collections.emptyList();
}
List<String> paths = new ArrayList<String>();
for (String childName : childNames)
{
String path = parentPath + "/" + childName;
paths.add(path);
}
// remove null record
List<Stat> curStats = new ArrayList<Stat>(paths.size());
List<T> records = get(paths, curStats, options);
Iterator<T> recordIter = records.iterator();
Iterator<Stat> statIter = curStats.iterator();
while (statIter.hasNext())
{
recordIter.next();
if (statIter.next() == null)
{
statIter.remove();
recordIter.remove();
}
}
if (stats != null)
{
stats.clear();
stats.addAll(curStats);
}
return records;
}
catch (ZkNoNodeException e)
{
return Collections.emptyList();
}
}
/**
* sync getChildNames
*
* @return null if parentPath doesn't exist
*/
@Override
public List<String> getChildNames(String parentPath, int options)
{
try
{
List<String> childNames = _zkClient.getChildren(parentPath);
Collections.sort(childNames);
return childNames;
}
catch (ZkNoNodeException e)
{
return null;
}
}
/**
* sync exists
*
*/
@Override
public boolean exists(String path, int options)
{
return _zkClient.exists(path);
}
/**
* sync getStat
*
*/
@Override
public Stat getStat(String path, int options)
{
return _zkClient.getStat(path);
}
/**
* sync remove
*
*/
@Override
public boolean remove(String path, int options)
{
try
{
// optimize on common path
_zkClient.delete(path);
}
catch (ZkException e)
{
_zkClient.deleteRecursive(path);
}
return true;
}
/**
* async create. give up on error other than NONODE
*
*/
CreateCallbackHandler[] create(List<String> paths,
List<T> records,
boolean[] needCreate,
List<List<String>> pathsCreated,
int options)
{
if ((records != null && records.size() != paths.size())
|| needCreate.length != paths.size()
|| (pathsCreated != null && pathsCreated.size() != paths.size()))
{
throw new IllegalArgumentException("paths, records, needCreate, and pathsCreated should be of same size");
}
CreateCallbackHandler[] cbList = new CreateCallbackHandler[paths.size()];
CreateMode mode = AccessOption.getMode(options);
if (mode == null)
{
LOG.error("Invalid async set mode. options: " + options);
return cbList;
}
boolean retry;
do
{
retry = false;
for (int i = 0; i < paths.size(); i++)
{
if (!needCreate[i])
continue;
String path = paths.get(i);
T record = records == null ? null : records.get(i);
cbList[i] = new CreateCallbackHandler();
_zkClient.asyncCreate(path, record, mode, cbList[i]);
}
List<String> parentPaths =
new ArrayList<String>(Collections.<String> nCopies(paths.size(), null));
boolean failOnNoNode = false;
for (int i = 0; i < paths.size(); i++)
{
if (!needCreate[i])
continue;
CreateCallbackHandler cb = cbList[i];
cb.waitForSuccess();
String path = paths.get(i);
if (Code.get(cb.getRc()) == Code.NONODE)
{
String parentPath = new File(path).getParent();
parentPaths.set(i, parentPath);
failOnNoNode = true;
}
else
{
// if create succeed or fail on error other than NONODE,
// give up
needCreate[i] = false;
// if succeeds, record what paths we've created
if (Code.get(cb.getRc()) == Code.OK && pathsCreated != null)
{
if (pathsCreated.get(i) == null)
{
pathsCreated.set(i, new ArrayList<String>());
}
pathsCreated.get(i).add(path);
}
}
}
if (failOnNoNode)
{
boolean[] needCreateParent = Arrays.copyOf(needCreate, needCreate.length);
CreateCallbackHandler[] parentCbList =
create(parentPaths, null, needCreateParent, pathsCreated, AccessOption.PERSISTENT);
for (int i = 0; i < parentCbList.length; i++)
{
CreateCallbackHandler parentCb = parentCbList[i];
if (parentCb == null)
continue;
Code rc = Code.get(parentCb.getRc());
// if parent is created, retry create child
if (rc == Code.OK || rc == Code.NODEEXISTS)
{
retry = true;
break;
}
}
}
}
while (retry);
return cbList;
}
/**
* async create
*
* TODO: rename to create
*/
@Override
public boolean[] createChildren(List<String> paths, List<T> records, int options)
{
boolean[] success = new boolean[paths.size()];
CreateMode mode = AccessOption.getMode(options);
if (mode == null)
{
LOG.error("Invalid async create mode. options: " + options);
return success;
}
boolean[] needCreate = new boolean[paths.size()];
Arrays.fill(needCreate, true);
List<List<String>> pathsCreated =
new ArrayList<List<String>>(Collections.<List<String>> nCopies(paths.size(), null));
long startT = System.nanoTime();
try
{
CreateCallbackHandler[] cbList =
create(paths, records, needCreate, pathsCreated, options);
for (int i = 0; i < cbList.length; i++)
{
CreateCallbackHandler cb = cbList[i];
success[i] = (Code.get(cb.getRc()) == Code.OK);
}
return success;
}
finally
{
long endT = System.nanoTime();
if (LOG.isDebugEnabled())
{
LOG.debug("create_async, size: " + paths.size() + ", paths: " + paths.get(0)
+ ",... time: " + (endT - startT) + " ns");
}
}
}
/**
* async set
*
* TODO: rename to set
*
*/
@Override
public boolean[] setChildren(List<String> paths, List<T> records, int options)
{
return set(paths, records, null, null, options);
}
/**
* async set, give up on error other than NoNode
*
*/
boolean[] set(List<String> paths,
List<T> records,
List<List<String>> pathsCreated,
List<Stat> stats,
int options)
{
if (paths == null || paths.size() == 0)
{
return new boolean[0];
}
if ((records != null && records.size() != paths.size())
|| (pathsCreated != null && pathsCreated.size() != paths.size()))
{
throw new IllegalArgumentException("paths, records, and pathsCreated should be of same size");
}
boolean[] success = new boolean[paths.size()];
CreateMode mode = AccessOption.getMode(options);
if (mode == null)
{
LOG.error("Invalid async set mode. options: " + options);
return success;
}
List<Stat> setStats =
new ArrayList<Stat>(Collections.<Stat> nCopies(paths.size(), null));
SetDataCallbackHandler[] cbList = new SetDataCallbackHandler[paths.size()];
CreateCallbackHandler[] createCbList = null;
boolean[] needSet = new boolean[paths.size()];
Arrays.fill(needSet, true);
long startT = System.nanoTime();
try
{
boolean retry;
do
{
retry = false;
for (int i = 0; i < paths.size(); i++)
{
if (!needSet[i])
continue;
String path = paths.get(i);
T record = records.get(i);
cbList[i] = new SetDataCallbackHandler();
_zkClient.asyncSetData(path, record, -1, cbList[i]);
}
boolean failOnNoNode = false;
for (int i = 0; i < cbList.length; i++)
{
SetDataCallbackHandler cb = cbList[i];
cb.waitForSuccess();
Code rc = Code.get(cb.getRc());
switch (rc)
{
case OK:
setStats.set(i, cb.getStat());
needSet[i] = false;
break;
case NONODE:
// if fail on NoNode, try create the node
failOnNoNode = true;
break;
default:
// if fail on error other than NoNode, give up
needSet[i] = false;
break;
}
}
// if failOnNoNode, try create
if (failOnNoNode)
{
boolean[] needCreate = Arrays.copyOf(needSet, needSet.length);
createCbList = create(paths, records, needCreate, pathsCreated, options);
for (int i = 0; i < createCbList.length; i++)
{
CreateCallbackHandler createCb = createCbList[i];
if (createCb == null)
{
continue;
}
Code rc = Code.get(createCb.getRc());
switch (rc)
{
case OK:
setStats.set(i, ZNode.ZERO_STAT);
needSet[i] = false;
break;
case NODEEXISTS:
retry = true;
break;
default:
// if creation fails on error other than NodeExists
// no need to retry set
needSet[i] = false;
break;
}
}
}
}
while (retry);
// construct return results
for (int i = 0; i < cbList.length; i++)
{
SetDataCallbackHandler cb = cbList[i];
Code rc = Code.get(cb.getRc());
if (rc == Code.OK)
{
success[i] = true;
}
else if (rc == Code.NONODE)
{
CreateCallbackHandler createCb = createCbList[i];
if (Code.get(createCb.getRc()) == Code.OK)
{
success[i] = true;
}
}
}
if (stats != null)
{
stats.clear();
stats.addAll(setStats);
}
return success;
}
finally
{
long endT = System.nanoTime();
if (LOG.isDebugEnabled())
{
LOG.debug("setData_async, size: " + paths.size() + ", paths: " + paths.get(0)
+ ",... time: " + (endT - startT) + " ns");
}
}
}
// TODO: rename to update
/**
* async update
*/
@Override
public boolean[] updateChildren(List<String> paths,
List<DataUpdater<T>> updaters,
int options)
{
List<T> updateData = update(paths, updaters, null, null, options);
boolean[] success = new boolean[paths.size()]; // init to false
for (int i = 0; i < paths.size(); i++)
{
T data = updateData.get(i);
success[i] = (data != null);
}
return success;
}
/**
* async update
*
* return: updatedData on success or null on fail
*/
List<T> update(List<String> paths,
List<DataUpdater<T>> updaters,
List<List<String>> pathsCreated,
List<Stat> stats,
int options)
{
if (paths == null || paths.size() == 0)
{
LOG.error("paths is null or empty");
return Collections.emptyList();
}
if (updaters.size() != paths.size()
|| (pathsCreated != null && pathsCreated.size() != paths.size()))
{
throw new IllegalArgumentException("paths, updaters, and pathsCreated should be of same size");
}
List<Stat> setStats =
new ArrayList<Stat>(Collections.<Stat> nCopies(paths.size(), null));
List<T> updateData = new ArrayList<T>(Collections.<T> nCopies(paths.size(), null));
CreateMode mode = AccessOption.getMode(options);
if (mode == null)
{
LOG.error("Invalid update mode. options: " + options);
return updateData;
}
SetDataCallbackHandler[] cbList = new SetDataCallbackHandler[paths.size()];
CreateCallbackHandler[] createCbList = null;
boolean[] needUpdate = new boolean[paths.size()];
Arrays.fill(needUpdate, true);
long startT = System.nanoTime();
try
{
boolean retry;
do
{
retry = false;
boolean[] needCreate = new boolean[paths.size()]; // init'ed with false
boolean failOnNoNode = false;
// asycn read all data
List<Stat> curStats = new ArrayList<Stat>();
List<T> curDataList =
get(paths, curStats, Arrays.copyOf(needUpdate, needUpdate.length));
// async update
List<T> newDataList = new ArrayList<T>();
for (int i = 0; i < paths.size(); i++)
{
if (!needUpdate[i])
{
newDataList.add(null);
continue;
}
String path = paths.get(i);
DataUpdater<T> updater = updaters.get(i);
T newData = updater.update(curDataList.get(i));
newDataList.add(newData);
Stat curStat = curStats.get(i);
if (curStat == null)
{
// node not exists
failOnNoNode = true;
needCreate[i] = true;
}
else
{
cbList[i] = new SetDataCallbackHandler();
_zkClient.asyncSetData(path, newData, curStat.getVersion(), cbList[i]);
}
}
// wait for completion
boolean failOnBadVersion = false;
for (int i = 0; i < paths.size(); i++)
{
SetDataCallbackHandler cb = cbList[i];
if (cb == null)
continue;
cb.waitForSuccess();
switch (Code.get(cb.getRc()))
{
case OK:
updateData.set(i, newDataList.get(i));
setStats.set(i, cb.getStat());
needUpdate[i] = false;
break;
case NONODE:
failOnNoNode = true;
needCreate[i] = true;
break;
case BADVERSION:
failOnBadVersion = true;
break;
default:
// if fail on error other than NoNode or BadVersion
// will not retry
needUpdate[i] = false;
break;
}
}
// if failOnNoNode, try create
if (failOnNoNode)
{
createCbList = create(paths, newDataList, needCreate, pathsCreated, options);
for (int i = 0; i < paths.size(); i++)
{
CreateCallbackHandler createCb = createCbList[i];
if (createCb == null)
{
continue;
}
switch (Code.get(createCb.getRc()))
{
case OK:
needUpdate[i] = false;
updateData.set(i, newDataList.get(i));
setStats.set(i, ZNode.ZERO_STAT);
break;
case NODEEXISTS:
retry = true;
break;
default:
// if fail on error other than NodeExists
// will not retry
needUpdate[i] = false;
break;
}
}
}
// if failOnBadVersion, retry
if (failOnBadVersion)
{
retry = true;
}
}
while (retry);
if (stats != null)
{
stats.clear();
stats.addAll(setStats);
}
return updateData;
}
finally
{
long endT = System.nanoTime();
if (LOG.isDebugEnabled())
{
LOG.debug("setData_async, size: " + paths.size() + ", paths: " + paths.get(0)
+ ",... time: " + (endT - startT) + " ns");
}
}
}
/**
* async exists
*
*/
@Override
public boolean[] exists(List<String> paths, int options)
{
Stat[] stats = getStats(paths, options);
boolean[] exists = new boolean[paths.size()];
for (int i = 0; i < paths.size(); i++)
{
exists[i] = (stats[i] != null);
}
return exists;
}
/**
* async getStat
*
*/
@Override
public Stat[] getStats(List<String> paths, int options)
{
if (paths == null || paths.size() == 0)
{
LOG.error("paths is null or empty");
return new Stat[0];
}
Stat[] stats = new Stat[paths.size()];
long startT = System.nanoTime();
try
{
ExistsCallbackHandler[] cbList = new ExistsCallbackHandler[paths.size()];
for (int i = 0; i < paths.size(); i++)
{
String path = paths.get(i);
cbList[i] = new ExistsCallbackHandler();
_zkClient.asyncExists(path, cbList[i]);
}
for (int i = 0; i < cbList.length; i++)
{
ExistsCallbackHandler cb = cbList[i];
cb.waitForSuccess();
stats[i] = cb._stat;
}
return stats;
}
finally
{
long endT = System.nanoTime();
if (LOG.isDebugEnabled())
{
LOG.debug("exists_async, size: " + paths.size() + ", paths: " + paths.get(0)
+ ",... time: " + (endT - startT) + " ns");
}
}
}
/**
* async remove
*
*/
@Override
public boolean[] remove(List<String> paths, int options)
{
if (paths == null || paths.size() == 0)
{
return new boolean[0];
}
boolean[] success = new boolean[paths.size()];
DeleteCallbackHandler[] cbList = new DeleteCallbackHandler[paths.size()];
long startT = System.nanoTime();
try
{
for (int i = 0; i < paths.size(); i++)
{
String path = paths.get(i);
cbList[i] = new DeleteCallbackHandler();
_zkClient.asyncDelete(path, cbList[i]);
}
for (int i = 0; i < cbList.length; i++)
{
DeleteCallbackHandler cb = cbList[i];
cb.waitForSuccess();
success[i] = (cb.getRc() == 0);
}
return success;
}
finally
{
long endT = System.nanoTime();
if (LOG.isDebugEnabled())
{
LOG.debug("delete_async, size: " + paths.size() + ", paths: " + paths.get(0)
+ ",... time: " + (endT - startT) + " ns");
}
}
}
/**
* Subscribe to zookeeper data changes
*/
@Override
public void subscribeDataChanges(String path, IZkDataListener listener)
{
_zkClient.subscribeDataChanges(path, listener);
}
/**
* Unsubscribe to zookeeper data changes
*/
@Override
public void unsubscribeDataChanges(String path, IZkDataListener dataListener)
{
_zkClient.unsubscribeDataChanges(path, dataListener);
}
/**
* Subscrie to zookeeper data changes
*/
@Override
public List<String> subscribeChildChanges(String path, IZkChildListener listener)
{
return _zkClient.subscribeChildChanges(path, listener);
}
/**
* Unsubscrie to zookeeper data changes
*/
@Override
public void unsubscribeChildChanges(String path, IZkChildListener childListener)
{
_zkClient.unsubscribeChildChanges(path, childListener);
}
// simple test
public static void main(String[] args)
{
ZkClient zkclient = new ZkClient("localhost:2191");
zkclient.setZkSerializer(new ZNRecordSerializer());
ZkBaseDataAccessor<ZNRecord> accessor = new ZkBaseDataAccessor<ZNRecord>(zkclient);
// test async create
List<String> createPaths =
Arrays.asList("/test/child1/child1", "/test/child2/child2");
List<ZNRecord> createRecords =
Arrays.asList(new ZNRecord("child1"), new ZNRecord("child2"));
boolean[] needCreate = new boolean[createPaths.size()];
Arrays.fill(needCreate, true);
List<List<String>> pathsCreated =
new ArrayList<List<String>>(Collections.<List<String>> nCopies(createPaths.size(),
null));
accessor.create(createPaths,
createRecords,
needCreate,
pathsCreated,
AccessOption.PERSISTENT);
System.out.println("pathsCreated: " + pathsCreated);
// test async set
List<String> setPaths =
Arrays.asList("/test/setChild1/setChild1", "/test/setChild2/setChild2");
List<ZNRecord> setRecords =
Arrays.asList(new ZNRecord("setChild1"), new ZNRecord("setChild2"));
pathsCreated =
new ArrayList<List<String>>(Collections.<List<String>> nCopies(setPaths.size(),
null));
boolean[] success =
accessor.set(setPaths, setRecords, pathsCreated, null, AccessOption.PERSISTENT);
System.out.println("pathsCreated: " + pathsCreated);
System.out.println("setSuccess: " + Arrays.toString(success));
// test async update
List<String> updatePaths =
Arrays.asList("/test/updateChild1/updateChild1", "/test/setChild2/setChild2");
class TestUpdater implements DataUpdater<ZNRecord>
{
final ZNRecord _newData;
public TestUpdater(ZNRecord newData)
{
_newData = newData;
}
@Override
public ZNRecord update(ZNRecord currentData)
{
return _newData;
}
}
List<DataUpdater<ZNRecord>> updaters =
Arrays.asList((DataUpdater<ZNRecord>) new TestUpdater(new ZNRecord("updateChild1")),
(DataUpdater<ZNRecord>) new TestUpdater(new ZNRecord("updateChild2")));
pathsCreated =
new ArrayList<List<String>>(Collections.<List<String>> nCopies(updatePaths.size(),
null));
List<ZNRecord> updateRecords =
accessor.update(updatePaths, updaters, pathsCreated, null, AccessOption.PERSISTENT);
for (int i = 0; i < updatePaths.size(); i++)
{
success[i] = updateRecords.get(i) != null;
}
System.out.println("pathsCreated: " + pathsCreated);
System.out.println("updateSuccess: " + Arrays.toString(success));
System.out.println("CLOSING");
zkclient.close();
}
/**
* Reset
*/
@Override
public void reset()
{
// Nothing to do
}
}