final long startTime = System.currentTimeMillis();
// First things first: find Server nodes to talk to:
NodesForKey nodes = _clusterView.getNodesFor(key);
// then result
HeadOperationResult result = new HeadOperationResult(config.getOperationConfig());
// One sanity check: if not enough server nodes to talk to, can't succeed...
int nodeCount = nodes.size();
if (nodeCount < 1) {
return result; // or Exception?
}
// Then figure out how long we have for the whole operation; use same timeout as GET
final long endOfTime = startTime + config.getOperationConfig().getGetOperationTimeoutMsecs();
final long lastValidTime = endOfTime - config.getCallConfig().getMinimumTimeoutMsecs();
// Ok: first round; try HEAD from every enabled store (or, if only one try, all)
final boolean noRetries = !allowRetries();
List<NodeFailure> retries = null;
for (int i = 0; i < nodeCount; ++i) {
ClusterServerNode server = nodes.node(i);
if (!server.isDisabled() || noRetries) {
HeadCallResult gotten = server.entryHeader().tryHead(config.getCallConfig(), endOfTime, key);
if (gotten.failed()) {
CallFailure fail = gotten.getFailure();
if (fail.isRetriable()) {
retries = _add(retries, new NodeFailure(server, fail));
} else {
result.addFailed(new NodeFailure(server, fail));
}
continue;
}
if (gotten.hasContentLength()) {
return result.addFailed(retries).setContentLength(server, gotten.getContentLength());
}
// it not, it's 404, missing entry. Neither fail nor really success...
result = result.addMissing(server);
}
}
if (noRetries) { // if no retries, bail out quickly
return result.addFailed(retries);
}
final long secondRoundStart = System.currentTimeMillis();
// 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();
HeadCallResult gotten = server.entryHeader().tryHead(config.getCallConfig(), endOfTime, key);
if (gotten.succeeded()) {
if (gotten.hasContentLength()) {
return result.addFailed(retries).setContentLength(server, gotten.getContentLength());
}
// it not, it's 404, missing entry. Neither fail nor really success...
result = result.addMissing(server);
it.remove();
} else {
CallFailure fail = gotten.getFailure();
retry.addFailure(fail);
if (!fail.isRetriable()) {
result.addFailed(retry);
it.remove();
}
}
}
}
// if no success, add disabled nodes in the mix
for (int i = 0; i < nodeCount; ++i) {
ClusterServerNode server = nodes.node(i);
if (server.isDisabled()) {
if (System.currentTimeMillis() >= lastValidTime) {
return result.addFailed(retries);
}
HeadCallResult gotten = server.entryHeader().tryHead(config.getCallConfig(), endOfTime, key);
if (gotten.succeeded()) {
if (gotten.hasContentLength()) {
return result.addFailed(retries).setContentLength(server, gotten.getContentLength());
}
// it not, it's 404, missing entry. Neither fail nor really success...
result = result.addMissing(server);
} else {
CallFailure fail = gotten.getFailure();
if (fail.isRetriable()) {
retries.add(new NodeFailure(server, fail));
} else {
result.addFailed(new NodeFailure(server, fail));
}
}
}
}
long prevStartTime = secondRoundStart;
for (int i = 1; (i <= MAX_RETRIES_FOR_GET) && !retries.isEmpty(); ++i) {
final long currStartTime = System.currentTimeMillis();
_doDelay(prevStartTime, currStartTime, endOfTime);
Iterator<NodeFailure> it = retries.iterator();
while (it.hasNext()) {
if (System.currentTimeMillis() >= lastValidTime) {
return result.addFailed(retries);
}
NodeFailure retry = it.next();
ClusterServerNode server = (ClusterServerNode) retry.getServer();
HeadCallResult gotten = server.entryHeader().tryHead(config.getCallConfig(), endOfTime, key);
if (gotten.succeeded()) {
if (gotten.hasContentLength()) {
return result.addFailed(retries).setContentLength(server, gotten.getContentLength());
}
// it not, it's 404, missing entry. Neither fail nor really success...
result = result.addMissing(server);
it.remove();
} else {
CallFailure fail = gotten.getFailure();
retry.addFailure(fail);
if (!fail.isRetriable()) {
result.addFailed(retry);
it.remove();
}
}
}
}
// we are all done and this'll be a failure...
return result.addFailed(retries);
}