* @throws KeeperException
* @throws InterruptedException
*/
public Stat setData(String path, byte[] data, int version)
throws KeeperException, InterruptedException {
RetryCounter retryCounter = retryCounterFactory.create();
byte[] newData = appendMetaData(data);
while (true) {
try {
return zk.setData(path, newData, version);
} catch (KeeperException e) {
switch (e.code()) {
case CONNECTIONLOSS:
case OPERATIONTIMEOUT:
LOG.warn("Possibly transient ZooKeeper exception: " + e);
if (!retryCounter.shouldRetry()) {
LOG.error("ZooKeeper setData failed after "
+ retryCounter.getMaxRetries() + " retries");
throw e;
}
break;
case BADVERSION:
// try to verify whether the previous setData success or not
try{
Stat stat = new Stat();
byte[] revData = zk.getData(path, false, stat);
int idLength = Bytes.toInt(revData, ID_OFFSET);
int dataLength = revData.length-ID_OFFSET-idLength;
int dataOffset = ID_OFFSET+idLength;
if(Bytes.compareTo(revData, ID_OFFSET, id.length,
revData, dataOffset, dataLength) == 0) {
// the bad version is caused by previous successful setData
return stat;
}
} catch(KeeperException keeperException){
// the ZK is not reliable at this moment. just throw out exception
throw keeperException;
}
// throw out other exceptions and verified bad version exceptions
default:
throw e;
}
}
retryCounter.sleepUntilNextRetry();
retryCounter.useRetry();
}
}