in src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java [498:571]
void reschedule(FetchOne fetchOp, RetryReason reason) {
synchronized (stateLock) {
URIish uri = fetchOp.getURI();
FetchOne pendingFetchOp = pending.get(uri);
if (pendingFetchOp != null) {
// There is one FetchOp instance already pending to same URI.
if (pendingFetchOp.isRetrying()) {
// The one pending is one already retrying, so it should
// maintain it and add to it the refs of the one passed
// as parameter to the method.
// This scenario would happen if a FetchOp has started running
// and then before it failed due transport exception, another
// one to same URI started. The first one would fail and would
// be rescheduled, being present in pending list. When the
// second one fails, it will also be rescheduled and then,
// here, find out replication to its URI is already pending
// for retry (blocking).
pendingFetchOp.addRefs(fetchOp.getRefs());
pendingFetchOp.addStates(fetchOp.getStates());
fetchOp.removeStates();
} else {
// The one pending is one that is NOT retrying, it was just
// scheduled believing no problem would happen. The one pending
// should be canceled, and this is done by setting its canceled
// flag, removing it from pending list, and adding its refs to
// the fetchOp instance that should then, later, in this method,
// be scheduled for retry.
// Notice that the FetchOp found pending will start running and,
// when notifying it is starting (with pending lock protection),
// it will see it was canceled and then it will do nothing with
// pending list and it will not execute its run implementation.
pendingFetchOp.canceledByReplication();
pending.remove(uri);
fetchOp.addRefs(pendingFetchOp.getRefs());
fetchOp.addStates(pendingFetchOp.getStates());
pendingFetchOp.removeStates();
}
}
if (pendingFetchOp == null || !pendingFetchOp.isRetrying()) {
pending.put(uri, fetchOp);
switch (reason) {
case COLLISION:
pool.schedule(fetchOp, config.getRescheduleDelay(), TimeUnit.SECONDS);
break;
case TRANSPORT_ERROR:
case REPOSITORY_MISSING:
default:
RefUpdate.Result trackingRefUpdate =
RetryReason.REPOSITORY_MISSING.equals(reason)
? RefUpdate.Result.NOT_ATTEMPTED
: RefUpdate.Result.REJECTED_OTHER_REASON;
postReplicationFailedEvent(fetchOp, trackingRefUpdate);
if (fetchOp.setToRetry()) {
postReplicationScheduledEvent(fetchOp);
pool.schedule(fetchOp, config.getRetryDelay(), TimeUnit.MINUTES);
} else {
fetchOp.canceledByReplication();
pending.remove(uri);
stateLog.error(
"Fetch from " + fetchOp.getURI() + " cancelled after maximum number of retries",
fetchOp.getStatesAsArray());
}
break;
}
}
}
}