commandTopologyId, currentTopologyId);
throw new OutdatedTopologyException("Cache topology changed while the command was executing: expected " +
commandTopologyId + ", got " + currentTopologyId);
}
ValueMatcher valueMatcher = command.getValueMatcher();
if (!ctx.isOriginLocal()) {
if (primaryOwner.equals(rpcManager.getAddress())) {
if (!command.isSuccessful()) {
log.tracef("Skipping the replication of the conditional command as it did not succeed on primary owner (%s).", command);
return localResult;
}
List<Address> recipients = recipientGenerator.generateRecipients();
// Ignore the previous value on the backup owners
command.setValueMatcher(ValueMatcher.MATCH_ALWAYS);
try {
rpcManager.invokeRemotely(recipients, command, determineRpcOptionsForBackupReplication(rpcManager,
isSync, recipients));
} finally {
// Switch to the retry policy, in case the primary owner changed and the write already succeeded on the new primary
command.setValueMatcher(valueMatcher.matcherForRetry());
}
}
return localResult;
} else {
if (primaryOwner.equals(rpcManager.getAddress())) {
if (!command.isSuccessful()) {
log.tracef("Skipping the replication of the command as it did not succeed on primary owner (%s).", command);
return localResult;
}
List<Address> recipients = recipientGenerator.generateRecipients();
log.tracef("I'm the primary owner, sending the command to all the backups (%s) in order to be applied.",
recipients);
// check if a single owner has been configured and the target for the key is the local address
boolean isSingleOwnerAndLocal = cacheConfiguration.clustering().hash().numOwners() == 1;
if (!isSingleOwnerAndLocal) {
// Ignore the previous value on the backup owners
command.setValueMatcher(ValueMatcher.MATCH_ALWAYS);
try {
rpcManager.invokeRemotely(recipients, command, determineRpcOptionsForBackupReplication(rpcManager,
isSync, recipients));
} finally {
// Switch to the retry policy, in case the primary owner changed and the write already succeeded on the new primary
command.setValueMatcher(valueMatcher.matcherForRetry());
}
}
return localResult;
} else {
log.tracef("I'm not the primary owner, so sending the command to the primary owner(%s) in order to be forwarded", primaryOwner);
boolean isSyncForwarding = isSync || isNeedReliableReturnValues(command);
Map<Address, Response> addressResponseMap;
try {
addressResponseMap = rpcManager.invokeRemotely(Collections.singletonList(primaryOwner), command,
rpcManager.getDefaultRpcOptions(isSyncForwarding));
} catch (RemoteException e) {
Throwable ce = e;
while (ce instanceof RemoteException) {
ce = ce.getCause();
}
if (ce instanceof OutdatedTopologyException) {
// If the primary owner throws an OutdatedTopologyException, it must be because the command succeeded there
if (trace) log.tracef("Changing the value matching policy from %s to %s (original value was %s)",
command.getValueMatcher(), valueMatcher.matcherForRetry(), valueMatcher);
command.setValueMatcher(valueMatcher.matcherForRetry());
}
throw e;
} catch (SuspectException e) {
// If the primary owner became suspected, we don't know if it was able to replicate it's data properly
// to all backup owners and notify all listeners, thus we need to retry with new matcher in case if
// it had updated the backup owners
if (trace) log.tracef("Primary owner suspected - Changing the value matching policy from %s to %s " +
"(original value was %s)", command.getValueMatcher(),
valueMatcher.matcherForRetry(), valueMatcher);
command.setValueMatcher(valueMatcher.matcherForRetry());
throw e;
}
if (!isSyncForwarding) return localResult;
Object primaryResult = getResponseFromPrimaryOwner(primaryOwner, addressResponseMap);