use of org.infinispan.commands.TopologyAffectedCommand in project infinispan by infinispan.
the class BaseStateTransferInterceptor method handleExceptionOnReadCommandReturn.
private Object handleExceptionOnReadCommandReturn(InvocationContext rCtx, VisitableCommand rCommand, Throwable t) throws Throwable {
Throwable ce = t;
while (ce instanceof RemoteException) {
ce = ce.getCause();
}
TopologyAffectedCommand cmd = (TopologyAffectedCommand) rCommand;
final CacheTopology cacheTopology = distributionManager.getCacheTopology();
int currentTopologyId = cacheTopology.getTopologyId();
int requestedTopologyId;
if (ce instanceof SuspectException) {
// Read commands must ignore CacheNotFoundResponses
throw new IllegalStateException("Read commands must ignore leavers");
} else if (ce instanceof OutdatedTopologyException) {
logRetry(currentTopologyId, cmd);
// We can get OTE for dist reads even if current topology information is sufficient:
// 1. A has topology in phase READ_ALL_WRITE_ALL, sends message to both old owner B and new C
// 2. C has old topology with READ_OLD_WRITE_ALL, so it responds with UnsureResponse
// 3. C updates topology to READ_ALL_WRITE_ALL, B updates to READ_NEW_WRITE_ALL
// 4. B receives the read, but it already can't read: responds with UnsureResponse
// 5. A receives two unsure responses and throws OTE
// However, now we are sure that we can immediately retry the request, because C must have updated its topology
OutdatedTopologyException ote = (OutdatedTopologyException) ce;
requestedTopologyId = cmd.getTopologyId() + ote.topologyIdDelta;
} else if (ce instanceof AllOwnersLostException) {
if (getLog().isTraceEnabled())
getLog().tracef("All owners for command %s have been lost.", cmd);
// In scattered cache it might be common to lose the single owner, we need to retry. We will find out that
// we can return null only after the next topology is installed. If partition handling is enabled we decide
// only based on the availability status.
// In other cache modes, during partition the exception is already handled in PartitionHandlingInterceptor,
// and if the handling is not enabled, we can't but return null.
requestedTopologyId = cmd.getTopologyId() + 1;
} else {
throw t;
}
// Only retry once if currentTopologyId > cmdTopologyId + 1
int retryTopologyId = Math.max(currentTopologyId, requestedTopologyId);
cmd.setTopologyId(retryTopologyId);
((FlagAffectedCommand) cmd).addFlags(FlagBitSets.COMMAND_RETRY);
if (retryTopologyId == currentTopologyId) {
return invokeNextAndHandle(rCtx, rCommand, handleReadCommandReturn);
} else {
return makeStage(asyncInvokeNext(rCtx, rCommand, stateTransferLock.transactionDataFuture(retryTopologyId))).andHandle(rCtx, rCommand, handleReadCommandReturn);
}
}
use of org.infinispan.commands.TopologyAffectedCommand in project infinispan by infinispan.
the class InvalidationInterceptor method invalidateAcrossCluster.
private CompletionStage<Void> invalidateAcrossCluster(InvocationContext ctx, Object[] keys, boolean synchronous, boolean onePhaseCommit, int topologyId) throws Throwable {
// increment invalidations counter if statistics maintained
incrementInvalidations();
final InvalidateCommand invalidateCommand = commandsFactory.buildInvalidateCommand(EnumUtil.EMPTY_BIT_SET, keys);
TopologyAffectedCommand command = invalidateCommand;
if (ctx.isInTxScope()) {
TxInvocationContext txCtx = (TxInvocationContext) ctx;
// A Prepare command containing the invalidation command in its 'modifications' list is sent to the remote nodes
// so that the invalidation is executed in the same transaction and locks can be acquired and released properly.
command = commandsFactory.buildPrepareCommand(txCtx.getGlobalTransaction(), Collections.singletonList(invalidateCommand), onePhaseCommit);
}
command.setTopologyId(topologyId);
if (synchronous) {
return rpcManager.invokeCommandOnAll(command, VoidResponseCollector.ignoreLeavers(), rpcManager.getSyncRpcOptions());
} else {
rpcManager.sendToAll(command, DeliverOrder.NONE);
return CompletableFutures.completedNull();
}
}
use of org.infinispan.commands.TopologyAffectedCommand in project infinispan by infinispan.
the class RpcManagerImpl method setTopologyId.
private void setTopologyId(ReplicableCommand command) {
if (command instanceof TopologyAffectedCommand) {
TopologyAffectedCommand topologyAffectedCommand = (TopologyAffectedCommand) command;
if (topologyAffectedCommand.getTopologyId() == -1) {
int currentTopologyId = distributionManager.getCacheTopology().getTopologyId();
if (log.isTraceEnabled()) {
log.tracef("Topology id missing on command %s, setting it to %d", command, currentTopologyId);
}
topologyAffectedCommand.setTopologyId(currentTopologyId);
}
}
}
use of org.infinispan.commands.TopologyAffectedCommand in project infinispan by infinispan.
the class BaseDistributionInterceptor method handleFunctionalReadManyCommand.
protected <C extends TopologyAffectedCommand & FlagAffectedCommand> Object handleFunctionalReadManyCommand(InvocationContext ctx, C command, ReadManyCommandHelper<C> helper) {
// TODO: repeatable-reads are not implemented - see visitReadOnlyKeyCommand
if (command.hasAnyFlag(FlagBitSets.CACHE_MODE_LOCAL | FlagBitSets.SKIP_REMOTE_LOOKUP)) {
return handleLocalOnlyReadManyCommand(ctx, command, helper.keys(command));
}
LocalizedCacheTopology cacheTopology = checkTopologyId(command);
Collection<?> keys = helper.keys(command);
if (!ctx.isOriginLocal()) {
return handleRemoteReadManyCommand(ctx, command, keys, helper);
}
if (keys.isEmpty()) {
return Stream.empty();
}
ConsistentHash ch = cacheTopology.getReadConsistentHash();
int estimateForOneNode = 2 * keys.size() / ch.getMembers().size();
List<Object> availableKeys = new ArrayList<>(estimateForOneNode);
Map<Address, List<Object>> requestedKeys = getKeysByOwner(ctx, keys, cacheTopology, availableKeys, null);
CompletionStage<Void> requiredKeysFuture = helper.fetchRequiredKeys(cacheTopology, requestedKeys, availableKeys, ctx, command);
if (requiredKeysFuture == null) {
return asyncValue(fetchAndApplyValues(ctx, command, helper, keys, availableKeys, requestedKeys));
} else {
// b) fetchAndApplyValues invokes the command on availableKeys and stores the result
return asyncValue(requiredKeysFuture.thenCompose(nil -> fetchAndApplyValues(ctx, command, helper, keys, availableKeys, requestedKeys)));
}
}
use of org.infinispan.commands.TopologyAffectedCommand in project infinispan by infinispan.
the class PessimisticLockingInterceptor method lockAndRecordForManyKeysCommand.
private Object lockAndRecordForManyKeysCommand(InvocationContext ctx, FlagAffectedCommand command, Collection<?> keys) {
if (!needRemoteLocks(ctx, keys, command)) {
return acquireLocalLocksAndInvokeNext(ctx, command, keys);
} else {
final TxInvocationContext txContext = (TxInvocationContext) ctx;
LockControlCommand lcc = cf.buildLockControlCommand(keys, command.getFlagsBitSet(), txContext.getGlobalTransaction());
if (command instanceof TopologyAffectedCommand) {
lcc.setTopologyId(((TopologyAffectedCommand) command).getTopologyId());
}
// the chain again with the actual command
return invokeNextThenApply(ctx, lcc, (rCtx, rCommand, rv) -> acquireLocalLocksAndInvokeNext(rCtx, command, keys));
}
}
Aggregations