private void updateTopologyId(TopologyAffectedCommand command) throws InterruptedException { // set the topology id if it was not set before (ie. this is local command) // TODO Make tx commands extend FlagAffectedCommand so we can use CACHE_MODE_LOCAL in // TransactionTable.cleanupStaleTransactions if (command.getTopologyId() == -1) { CacheTopology cacheTopology = stateTransferManager.getCacheTopology(); if (cacheTopology != null) { command.setTopologyId(cacheTopology.getTopologyId()); } } }
/** * For non-tx write commands, we retry the command locally if the topology changed, instead of * forwarding to the new owners like we do for tx commands. But we only retry on the originator, * and only if the command doesn't have the {@code CACHE_MODE_LOCAL} flag. */ private Object handleNonTxWriteCommand(InvocationContext ctx, WriteCommand command) throws Throwable { log.tracef("handleNonTxWriteCommand for command %s", command); if (isLocalOnly(ctx, command)) { return invokeNextInterceptor(ctx, command); } updateTopologyId(command); // Only catch OutdatedTopologyExceptions on the originator if (!ctx.isOriginLocal()) { return invokeNextInterceptor(ctx, command); } int commandTopologyId = command.getTopologyId(); Object localResult; try { localResult = invokeNextInterceptor(ctx, command); return localResult; } catch (CacheException e) { Throwable ce = e; while (ce instanceof RemoteException) { ce = ce.getCause(); } if (!(ce instanceof OutdatedTopologyException)) throw e; log.tracef("Retrying command because of topology change: %s", command); // We increment the topology id so that updateTopologyIdAndWaitForTransactionData waits for // the next topology. // Without this, we could retry the command too fast and we could get the // OutdatedTopologyException again. int newTopologyId = Math.max(stateTransferManager.getCacheTopology().getTopologyId(), commandTopologyId + 1); command.setTopologyId(newTopologyId); stateTransferLock.waitForTransactionData( newTopologyId, transactionDataTimeout, TimeUnit.MILLISECONDS); localResult = handleNonTxWriteCommand(ctx, command); } // We retry the command every time the topology changes, either in // NonTxConcurrentDistributionInterceptor or in // EntryWrappingInterceptor. So we don't need to forward the command again here (without holding // a lock). // stateTransferManager.forwardCommandIfNeeded(command, command.getAffectedKeys(), // ctx.getOrigin(), false); return localResult; }