private String createSequential(String path, byte[] data, List<ACL> acl, CreateMode createMode) throws KeeperException, InterruptedException { RetryCounter retryCounter = retryCounterFactory.create(); boolean first = true; String newPath = path + this.identifier; while (true) { try { if (!first) { // Check if we succeeded on a previous attempt String previousResult = findPreviousSequentialNode(newPath); if (previousResult != null) { return previousResult; } } first = false; return zk.create(newPath, data, acl, createMode); } catch (KeeperException e) { switch (e.code()) { case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "create"); break; default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); } }
private String createNonSequential(String path, byte[] data, List<ACL> acl, CreateMode createMode) throws KeeperException, InterruptedException { RetryCounter retryCounter = retryCounterFactory.create(); boolean isRetry = false; // False for first attempt, true for all retries. while (true) { try { return zk.create(path, data, acl, createMode); } catch (KeeperException e) { switch (e.code()) { case NODEEXISTS: if (isRetry) { // If the connection was lost, there is still a possibility that // we have successfully created the node at our previous attempt, // so we read the node and compare. byte[] currentData = zk.getData(path, false, null); if (currentData != null && Bytes.compareTo(currentData, data) == 0) { // We successfully created a non-sequential node return path; } LOG.error( "Node " + path + " already exists with " + Bytes.toStringBinary(currentData) + ", could not write " + Bytes.toStringBinary(data)); throw e; } LOG.info("Node " + path + " already exists and this is not a " + "retry"); throw e; case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "create"); break; default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); isRetry = true; } }
/** * exists is an idempotent operation. Retry before throwing exception * * @return A Stat instance */ public Stat exists(String path, boolean watch) throws KeeperException, InterruptedException { RetryCounter retryCounter = retryCounterFactory.create(); while (true) { try { return zk.exists(path, watch); } catch (KeeperException e) { switch (e.code()) { case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "exists"); break; default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); } }
/** * setData is NOT an idempotent operation. Retry may cause BadVersion Exception Adding an * identifier field into the data to check whether badversion is caused by the result of previous * correctly setData * * @return Stat instance */ public Stat setData(String path, byte[] data, int version) throws KeeperException, InterruptedException { RetryCounter retryCounter = retryCounterFactory.create(); byte[] newData = appendMetaData(data); boolean isRetry = false; while (true) { try { return zk.setData(path, newData, version); } catch (KeeperException e) { switch (e.code()) { case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "setData"); break; case BADVERSION: if (isRetry) { // try to verify whether the previous setData success or not try { Stat stat = new Stat(); byte[] revData = zk.getData(path, false, stat); if (Bytes.compareTo(revData, newData) == 0) { // the bad version is caused by previous successful setData return stat; } } catch (KeeperException keeperException) { // the ZK is not reliable at this moment. just throwing exception throw keeperException; } } // throw other exceptions and verified bad version exceptions default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); isRetry = true; } }
/** Run multiple operations in a transactional manner. Retry before throwing exception */ public List<OpResult> multi(Iterable<Op> ops) throws KeeperException, InterruptedException { RetryCounter retryCounter = retryCounterFactory.create(); Iterable<Op> multiOps = prepareZKMulti(ops); while (true) { try { return zk.multi(multiOps); } catch (KeeperException e) { switch (e.code()) { case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "multi"); break; default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); } }
/** * getChildren is an idempotent operation. Retry before throwing exception * * @return List of children znodes */ public List<String> getChildren(String path, Watcher watcher) throws KeeperException, InterruptedException { RetryCounter retryCounter = retryCounterFactory.create(); while (true) { try { return zk.getChildren(path, watcher); } catch (KeeperException e) { switch (e.code()) { case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "getChildren"); break; default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); } }
/** * getData is an idemnpotent operation. Retry before throwing exception * * @return Data */ public byte[] getData(String path, boolean watch, Stat stat) throws KeeperException, InterruptedException { RetryCounter retryCounter = retryCounterFactory.create(); while (true) { try { byte[] revData = zk.getData(path, watch, stat); return this.removeMetaData(revData); } catch (KeeperException e) { switch (e.code()) { case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "getData"); break; default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); } }
/** * delete is an idempotent operation. Retry before throwing exception. This function will not * throw NoNodeException if the path does not exist. */ public void delete(String path, int version) throws InterruptedException, KeeperException { RetryCounter retryCounter = retryCounterFactory.create(); boolean isRetry = false; // False for first attempt, true for all retries. while (true) { try { zk.delete(path, version); return; } catch (KeeperException e) { switch (e.code()) { case NONODE: if (isRetry) { LOG.info( "Node " + path + " already deleted. Assuming that a " + "previous attempt succeeded."); return; } LOG.warn("Node " + path + " already deleted, and this is not a " + "retry"); throw e; case CONNECTIONLOSS: case SESSIONEXPIRED: case OPERATIONTIMEOUT: retryOrThrow(retryCounter, e, "delete"); break; default: throw e; } } retryCounter.sleepUntilNextRetry(); retryCounter.useRetry(); isRetry = true; } }