{
final long startTime = System.currentTimeMillis();
// First things first: find Server nodes to talk to:
NodesForKey nodes = _clusterView.getNodesFor(key);
DeleteOperationResult result = new DeleteOperationResult(config.getOperationConfig());
// One sanity check: if not enough server nodes to talk to, can't succeed...
int nodeCount = nodes.size();
if (nodeCount < config.getOperationConfig().getMinimalOksToSucceed()) {
return result; // or Exception?
}
// Then figure out how long we have for the whole operation
final long endOfTime = startTime + config.getOperationConfig().getGetOperationTimeoutMsecs();
final long lastValidTime = endOfTime - config.getCallConfig().getMinimumTimeoutMsecs();
/* Ok: first round; try DETE from every enabled store, up to optimal number
* of successes we expect.
*/
final boolean noRetries = !allowRetries();
List<NodeFailure> retries = null;
for (int i = 0; i < nodeCount; ++i) {
ClusterServerNode server = nodes.node(i);
if (server.isDisabled() && !noRetries) { // should be able to break, but let's double check
break;
}
CallFailure fail = server.entryDeleter().tryDelete(config.getCallConfig(), endOfTime, key);
if (fail != null) {
if (fail.isRetriable()) {
retries = _add(retries, new NodeFailure(server, fail));
} else {
result.addFailed(new NodeFailure(server, fail));
}
continue;
}
result.addSucceeded(server);
// first round: go to the max, if possible
if (result.succeededMaximally()) {
return result.addFailed(retries);
}
}
if (noRetries) { // if no retries, bail out quickly
return result.addFailed(retries);
}
/* If we got this far, let's accept 'just optimal'; but keep on trying for
* optimal since deletion via expiration is much more costly than explicit
* DELETEs.
*/
final long secondRoundStart = System.currentTimeMillis();
if (result.succeededOptimally() || secondRoundStart >= lastValidTime) {
return result.addFailed(retries);
}
// Do we need any delay in between?
_doDelay(startTime, secondRoundStart, endOfTime);
// Otherwise: go over retry list first, and if that's not enough, try disabled
if (retries == null) {
retries = new LinkedList<NodeFailure>();
} else {
Iterator<NodeFailure> it = retries.iterator();
while (it.hasNext()) {
NodeFailure retry = it.next();
ClusterServerNode server = (ClusterServerNode) retry.getServer();
CallFailure fail = server.entryDeleter().tryDelete(config.getCallConfig(), endOfTime, key);
if (fail != null) {
retry.addFailure(fail);
if (!fail.isRetriable()) { // not worth retrying?
result.addFailed(retry);
it.remove();
}
} else {
it.remove(); // remove now from retry list
result.addSucceeded(server);
if (result.succeededOptimally()) {
return result.addFailed(retries);
}
}
}
}
// if no success, add disabled nodes in the mix; but only if we don't have minimal success:
for (int i = 0; i < nodeCount; ++i) {
if (result.succeededMinimally() || System.currentTimeMillis() >= lastValidTime) {
return result.addFailed(retries);
}
ClusterServerNode server = nodes.node(i);
if (server.isDisabled()) {
CallFailure fail = server.entryDeleter().tryDelete(config.getCallConfig(), endOfTime, key);
if (fail != null) {
if (fail.isRetriable()) {
retries.add(new NodeFailure(server, fail));
} else {
result.addFailed(new NodeFailure(server, fail));
}
} else {
result.addSucceeded(server);
}
}
}
long prevStartTime = secondRoundStart;
for (int i = 1; (i <= MAX_RETRIES_FOR_DELETE) && !retries.isEmpty(); ++i) {
final long currStartTime = System.currentTimeMillis();
_doDelay(prevStartTime, currStartTime, endOfTime);
// and off we go again...
Iterator<NodeFailure> it = retries.iterator();
while (it.hasNext()) {
if (result.succeededMinimally() || System.currentTimeMillis() >= lastValidTime) {
return result.addFailed(retries);
}
NodeFailure retry = it.next();
ClusterServerNode server = retry.getServer();
CallFailure fail = server.entryDeleter().tryDelete(config.getCallConfig(), endOfTime, key);
if (fail != null) {
retry.addFailure(fail);
if (!fail.isRetriable()) {
result.addFailed(retry);
it.remove();
}
} else {
result.addSucceeded(server);
}
}
prevStartTime = currStartTime;
}
// we are all done, failed:
return result.addFailed(retries);
}