@Override public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) { if (command.isOnePhaseCommit()) { return invokeNextThenAccept(ctx, command, commitModificationsToIndex); } else { return invokeNext(ctx, command); } }
recipientSizeStat = NUM_NODES_PREPARE; commandSizeStat = PREPARE_COMMAND_SIZE; globalTransaction = ((PrepareCommand) command).getGlobalTransaction(); } else if (command instanceof RollbackCommand) { durationStat = SYNC_ROLLBACK_TIME; counterStat = NUM_SYNC_ROLLBACK; recipientSizeStat = NUM_NODES_ROLLBACK; globalTransaction = ((RollbackCommand) command).getGlobalTransaction(); } else if (command instanceof CommitCommand) { durationStat = SYNC_COMMIT_TIME; recipientSizeStat = NUM_NODES_COMMIT; commandSizeStat = COMMIT_COMMAND_SIZE; globalTransaction = ((CommitCommand) command).getGlobalTransaction(); } else if (command instanceof TxCompletionNotificationCommand) { durationStat = ASYNC_COMPLETE_NOTIFY_TIME;
@Override public Object visitRollbackCommand(TxInvocationContext ctx, RollbackCommand command) throws Throwable { return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> { seen(command.getGlobalTransaction(), rCtx.isOriginLocal()); }); }
PrepareCommand c11 = new PrepareCommand(cacheName, gtx, true, c5, c6, c8, c10); marshallAndAssertEquality(c11); CommitCommand c12 = new CommitCommand(cacheName, gtx); marshallAndAssertEquality(c12); RollbackCommand c13 = new RollbackCommand(cacheName, gtx); marshallAndAssertEquality(c13); TotalOrderNonVersionedPrepareCommand c14 = new TotalOrderNonVersionedPrepareCommand(cacheName, gtx, c5, c6, c8, c10); marshallAndAssertEquality(c14); TotalOrderVersionedPrepareCommand c15 = new TotalOrderVersionedPrepareCommand(cacheName, gtx, Arrays.asList(c5, c10), true); c15.setVersionsSeen(new EntryVersionsMap()); marshallAndAssertEquality(c15); TotalOrderRollbackCommand c16 = new TotalOrderRollbackCommand(cacheName, gtx); marshallAndAssertEquality(c16); TotalOrderCommitCommand c17 = new TotalOrderCommitCommand(cacheName, gtx); marshallAndAssertEquality(c17); TotalOrderVersionedCommitCommand c18 = new TotalOrderVersionedCommitCommand(cacheName, gtx); marshallAndAssertEquality(c18);
private Object broadcastInvalidateForPrepare(InvocationContext rCtx, VisitableCommand rCommand, Object rv) throws Throwable { log.tracef( "Entering InvalidationInterceptor's prepare phase. Ctx flags are empty" ); // fetch the modifications before the transaction is committed (and thus removed from the txTable) TxInvocationContext txCtx = (TxInvocationContext) rCtx; if ( shouldInvokeRemoteTxCommand( txCtx ) ) { if ( txCtx.getTransaction() == null ) { throw new IllegalStateException( "We must have an associated transaction" ); } PrepareCommand prepareCmd = (PrepareCommand) rCommand; List<WriteCommand> mods = Arrays.asList( prepareCmd.getModifications() ); CompletionStage<Void> completion = broadcastInvalidateForPrepare(mods, txCtx); if (completion != null) { return asyncValue(completion); } else { return rv; } } else { log.tracef( "Nothing to invalidate - no modifications in the transaction." ); } return rv; }
@Override public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) throws Throwable { GlobalTransaction globalTransaction = command.getGlobalTransaction(); if (trace) { log.tracef("Visit Prepare command %s. Is it local?. Transaction is %s", command, ctx.isOriginLocal(), globalTransaction.globalId()); } initStatsIfNecessary(ctx); cacheStatisticManager.onPrepareCommand(globalTransaction, ctx.isOriginLocal()); if (command.hasModifications()) { cacheStatisticManager.markAsWriteTransaction(globalTransaction, ctx.isOriginLocal()); } long start = timeService.time(); return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> { if (t != null) { processWriteException(rCtx, globalTransaction, t); } else { long end = timeService.time(); updateTime(PREPARE_EXECUTION_TIME, NUM_PREPARE_COMMAND, start, end, globalTransaction, rCtx .isOriginLocal()); } if (((PrepareCommand) rCommand).isOnePhaseCommit()) { boolean local = rCtx.isOriginLocal(); boolean success = t == null; cacheStatisticManager.setTransactionOutcome(success, globalTransaction, rCtx.isOriginLocal()); cacheStatisticManager.terminateTransaction(globalTransaction, local, !local); } }); }
@Override public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) throws Throwable { return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> { seen(command.getGlobalTransaction(), rCtx.isOriginLocal()); }); }
@Override public Object visitCommitCommand(TxInvocationContext ctx, CommitCommand command) throws Throwable { return invokeNextAndFinally(ctx, command, (rCtx, rCommand, rv, t) -> { seen(command.getGlobalTransaction(), rCtx.isOriginLocal()); }); }
/** * Rollbacks a transaction that is remove in all the cluster members. */ public final void rollbackRemoteTransaction(GlobalTransaction gtx) { RpcManager rpcManager = cache.getRpcManager(); CommandsFactory factory = cache.getComponentRegistry().getCommandsFactory(); try { RollbackCommand rollbackCommand = factory.buildRollbackCommand(gtx); rollbackCommand.setTopologyId(rpcManager.getTopologyId()); CompletionStage<Void> cs = rpcManager .invokeCommandOnAll(rollbackCommand, validOnly(), rpcManager.getSyncRpcOptions()); factory.initializeReplicableCommand(rollbackCommand, false); rollbackCommand.invokeAsync().join(); cs.toCompletableFuture().join(); } catch (Throwable throwable) { throw Util.rewrapAsCacheException(throwable); } finally { forgetTransaction(gtx, rpcManager, factory); } }
/** * Commits a remote 1PC transaction that is already in MARK_COMMIT state */ public int onePhaseCommitRemoteTransaction(GlobalTransaction gtx, List<WriteCommand> modifications) { RpcManager rpcManager = cache.getRpcManager(); CommandsFactory factory = cache.getComponentRegistry().getCommandsFactory(); try { //only pessimistic tx are committed in 1PC and it doesn't use versions. PrepareCommand command = factory.buildPrepareCommand(gtx, modifications, true); CompletionStage<Void> cs = rpcManager.invokeCommandOnAll(command, validOnly(), rpcManager.getSyncRpcOptions()); factory.initializeReplicableCommand(command, false); command.invokeAsync().join(); cs.toCompletableFuture().join(); forgetTransaction(gtx, rpcManager, factory); return loggingCompleted(true) == Status.OK ? XAResource.XA_OK : XAException.XAER_RMERR; } catch (Throwable throwable) { //transaction should commit but we still can have exceptions (timeouts or similar) return XAException.XAER_RMERR; } }
private Object visitSecondPhaseCommand(TxInvocationContext ctx, TransactionBoundaryCommand command, boolean commit, ExtendedStatistic duration, ExtendedStatistic counter) throws Throwable { GlobalTransaction globalTransaction = command.getGlobalTransaction(); if (trace) { log.tracef("Visit 2nd phase command %s. Is it local? %s. Transaction is %s", command, ctx.isOriginLocal(), globalTransaction.globalId()); } long start = timeService.time(); return invokeNextThenAccept(ctx, command, (rCtx, rCommand, rv) -> { long end = timeService.time(); updateTime(duration, counter, start, end, globalTransaction, rCtx.isOriginLocal()); cacheStatisticManager.setTransactionOutcome(commit, globalTransaction, rCtx.isOriginLocal()); cacheStatisticManager.terminateTransaction(globalTransaction, true, true); }); }
private void rollbackRemote(ComponentRegistry cr, CacheXid cacheXid, TxState state) { RollbackCommand rpcCommand = cr.getCommandsFactory().buildRollbackCommand(state.getGlobalTransaction()); RpcManager rpcManager = cr.getComponent(RpcManager.class); rpcCommand.setTopologyId(rpcManager.getTopologyId()); rpcManager.invokeCommandOnAll(rpcCommand, VoidResponseCollector.validOnly(), rpcManager.getSyncRpcOptions()) .thenRun(() -> { //ignore exception so the rollback can be retried. //if a node doesn't find the remote transaction, it returns null. TxFunction function = new SetCompletedTransactionFunction(false); rwMap.eval(cacheXid, function); }); }
rpcCommand = cr.getCommandsFactory().buildCommitCommand(state.getGlobalTransaction()); rpcCommand.setTopologyId(rpcManager.getTopologyId()); rpcManager.invokeCommandOnAll(rpcCommand, VoidResponseCollector.validOnly(), rpcManager.getSyncRpcOptions()) .handle((aVoid, throwable) -> {
if (!(command instanceof VersionedCommitCommand)) return false; GlobalTransaction gtx = ((VersionedCommitCommand) command).getGlobalTransaction(); LocalTransaction tx = transactionTable(1).getLocalTransaction(gtx); return tx.getStateTransferFlag() == null;
@Override public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand cmd) throws Throwable { try { // first pass up chain return invokeNextInterceptor(ctx, cmd); } finally { if (!ctx.isOriginLocal() || watchLocal) { logCommand(cmd); for (WriteCommand mod : cmd.getModifications()) logCommand(mod); } } }
@Override public Object visitRollbackCommand(TxInvocationContext ctx, RollbackCommand command) throws Throwable { if (!ctx.isOriginLocal()) { log.debugf("Received remote rollback for transaction %s", command.getGlobalTransaction()); numberRollbacks.incrementAndGet(); } return invokeNextInterceptor(ctx, command); }
@Override public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) throws Throwable { if (!ctx.isOriginLocal()) { log.debugf("Received remote prepare for transaction %s", command.getGlobalTransaction()); numberPrepares.incrementAndGet(); } return invokeNextInterceptor(ctx, command); }
@Override public Object visitCommitCommand(TxInvocationContext ctx, CommitCommand command) throws Throwable { if (!ctx.isOriginLocal()) { log.debugf("Received remote commit for transaction %s", command.getGlobalTransaction()); numberCommits.incrementAndGet(); } return invokeNextInterceptor(ctx, command); }
@Override public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) throws Throwable { if (ctx.isOriginLocal()) { // We can't wait to commit phase to remove the entry locally (invalidations are processed in 1pc // on remote nodes, so only local case matters here). The problem is that while the entry is locked // reads still can take place and we can read outdated collection after reading updated entity // owning this collection from DB; when this happens, the version lock on entity cannot protect // us against concurrent modification of the collection. Therefore, we need to remove the entry // here (even without lock!) and let possible update happen in commit phase. for (WriteCommand wc : command.getModifications()) { for (Object key : wc.getAffectedKeys()) { dataContainer.remove(key); } } } else { for (WriteCommand wc : command.getModifications()) { Collection<?> keys = wc.getAffectedKeys(); if (log.isTraceEnabled()) { log.tracef("Invalidating keys %s with lock owner %s", keys, ctx.getLockOwner()); } for (Object key : keys ) { putFromLoadValidator.beginInvalidatingKey(ctx.getLockOwner(), key); } } } return invokeNext(ctx, command); }
private boolean isUpdatingKeyWithValue(VisitableCommand command, Object key, Object value) { if (command instanceof PutKeyValueCommand) { return key.equals(((PutKeyValueCommand) command).getKey()) && value.equals(((PutKeyValueCommand) command).getValue()); } else if (command instanceof RemoveCommand) { return key.equals(((RemoveCommand) command).getKey()); } else if (command instanceof ClearCommand) { return true; } else if (command instanceof WriteOnlyManyEntriesCommand) { InternalCacheValue icv = (InternalCacheValue) ((WriteOnlyManyEntriesCommand) command).getArguments().get(key); return Objects.equals(icv.getValue(), value); } else if (command instanceof PrepareCommand) { for (WriteCommand writeCommand : ((PrepareCommand) command).getModifications()) { if (isUpdatingKeyWithValue(writeCommand, key, value)) { return true; } } } return false; }