/** {@inheritDoc} */ @Override public TransactionState state() { return tx.state(); }
/** * @param tx Transaction. * @return {@code True} if given transaction is explicitly started user transaction. */ private boolean activeUserTx(@Nullable IgniteInternalTx tx) { if (tx != null && tx.user() && tx.state() == ACTIVE) { assert tx instanceof GridNearTxLocal : tx; return true; } return false; }
/** {@inheritDoc} */ @Override public void onDisconnected(IgniteFuture reconnectFut) { txFinishSync.onDisconnected(reconnectFut); for (IgniteInternalTx tx : idMap.values()) { rollbackTx(tx, true, false); tx.state(ROLLING_BACK); tx.state(ROLLED_BACK); } for (IgniteInternalTx tx : nearIdMap.values()) { rollbackTx(tx, true, false); tx.state(ROLLING_BACK); tx.state(ROLLED_BACK); } IgniteClientDisconnectedException err = new IgniteClientDisconnectedException(reconnectFut, "Client node disconnected."); for (TxDeadlockFuture fut : deadlockDetectFuts.values()) fut.onDone(err); }
/** {@inheritDoc} */ @Override public IgniteInternalFuture<IgniteInternalTx> apply(IgniteInternalTx tx, IgniteTxManager tm) { return tx.isRollbackOnly() || tx.state() == COMMITTING || tx.state() == COMMITTED ? new GridFinishedFuture<>() : ((GridNearTxLocal)tx).rollbackNearTxLocalAsync(false, false); } }
/** {@inheritDoc} */ @Override public IgniteInternalFuture<IgniteInternalTx> apply(IgniteInternalTx tx, IgniteTxManager tm) { IgniteTxRemoteEx remote = (IgniteTxRemoteEx)tx; if (tx.isRollbackOnly() || tx.state() == COMMITTING || tx.state() == COMMITTED) return new GridFinishedFuture<>(); if (tx.state() == TransactionState.PREPARED) remote.doneRemote(tx.xidVersion(), Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList()); return tx.rollbackAsync(); } }
/** {@inheritDoc} */ @Override public void apply(StringBuilder sb, GridKernalContext ctx) { sb.append(U.nl()) .append("Related transactions [dhtVer=").append(dhtVer) .append(", nearVer=").append(nearVer).append("]: "); boolean found = false; for (IgniteInternalTx tx : ctx.cache().context().tm().activeTransactions()) { if (dhtVer.equals(tx.xidVersion()) || nearVer.equals(tx.nearXidVersion())) { sb.append(U.nl()) .append(" ") .append(tx.getClass().getSimpleName()) .append(" [ver=").append(tx.xidVersion()) .append(", nearVer=").append(tx.nearXidVersion()) .append(", topVer=").append(tx.topologyVersion()) .append(", state=").append(tx.state()) .append(", fullTx=").append(tx).append(']'); found = true; } } if (!found) sb.append(U.nl()).append("Failed to find related transactions."); }
@Override public void apply(IgniteInternalFuture<IgniteInternalTx> fut) { TransactionState state = tx.state(); if (log.isDebugEnabled()) log.debug("Near transaction finished with state: " + state); resFut.onDone(state == COMMITTED); } });
/** * Removes Tx from manager. Can be used only if there were no updates. * * @param tx Transaction to finish. */ public void forgetTx(IgniteInternalTx tx) { assert tx != null; if (transactionMap(tx).remove(tx.xidVersion(), tx)) { // 1. Remove from per-thread storage. clearThreadMap(tx); // 2. Unregister explicit locks. if (!tx.alternateVersions().isEmpty()) for (GridCacheVersion ver : tx.alternateVersions()) idMap.remove(ver); // 3. Remove Near-2-DHT mappings. if (tx instanceof GridCacheMappedVersion) mappedVers.remove(((GridCacheMappedVersion)tx).mappedVersion()); // 4. Clear context. resetContext(); // 5. Complete finish future. tx.state(UNKNOWN); } }
/** * @param nodeId Failed node ID. */ private void onNodeLeft(UUID nodeId) { if (msgLog.isInfoEnabled()) { msgLog.info("Tx recovery fut, mini future node left [txId=" + tx.nearXidVersion() + ", dhtTxId=" + tx.xidVersion() + ", node=" + nodeId + ", nearTxCheck=" + nearTxCheck + ']'); } if (nearTxCheck) { if (tx.state() == PREPARED) { Set<UUID> failedNodeIds0 = new HashSet<>(failedNodeIds); failedNodeIds0.add(nodeId); // Near and originating nodes left, need initiate tx check. cctx.tm().commitIfPrepared(tx, failedNodeIds0); } onDone(new ClusterTopologyCheckedException("Transaction node left grid (will ignore).")); } else onDone(true); }
/** * @param tx Transaction. * @return String view of all safe-to-print transaction properties. */ public static String txString(@Nullable IgniteInternalTx tx) { if (tx == null) return "null"; return tx.getClass().getSimpleName() + "[xid=" + tx.xid() + ", xidVersion=" + tx.xidVersion() + ", concurrency=" + tx.concurrency() + ", isolation=" + tx.isolation() + ", state=" + tx.state() + ", invalidate=" + tx.isInvalidate() + ", rollbackOnly=" + tx.isRollbackOnly() + ", nodeId=" + tx.nodeId() + ", timeout=" + tx.timeout() + ", duration=" + (U.currentTimeMillis() - tx.startTime()) + (tx instanceof GridNearTxLocal ? ", label=" + ((GridNearTxLocal)tx).label() : "") + ']'; }
/** * Count total number of holding locks on local node. */ private long txHoldingLockNum() { long holdingLockCounter = 0; IgniteTxManager tm = gridKernalCtx.cache().context().tm(); for (IgniteInternalTx tx : tm.activeTransactions()) { if ((tx.optimistic() && tx.state() == TransactionState.ACTIVE) || tx.empty() || !tx.local()) continue; holdingLockCounter++; } return holdingLockCounter; }
/** * Invalidates transaction. * * @param tx Transaction. * @param status Finalization status. */ private void salvageTx(IgniteInternalTx tx, IgniteInternalTx.FinalizationStatus status) { assert tx != null; TransactionState state = tx.state(); if (state == ACTIVE || state == PREPARING || state == PREPARED || state == MARKED_ROLLBACK) { if (!tx.markFinalizing(status)) { if (log.isInfoEnabled()) log.info("Will not try to commit invalidate transaction (could not mark finalized): " + tx); return; } tx.salvageTx(); if (log.isInfoEnabled()) log.info("Invalidated transaction because originating node left grid: " + CU.txString(tx)); } }
/** * Transaction start callback (has to do with when any operation was * performed on this transaction). * * @param tx Started transaction. * @return {@code True} if transaction is not in completed set. */ public boolean onStarted(IgniteInternalTx tx) { assert tx.state() == ACTIVE || tx.isRollbackOnly() : "Invalid transaction state [locId=" + cctx.localNodeId() + ", tx=" + tx + ']'; if (isCompleted(tx)) { ConcurrentMap<GridCacheVersion, IgniteInternalTx> txIdMap = transactionMap(tx); txIdMap.remove(tx.xidVersion(), tx); if (log.isDebugEnabled()) log.debug("Attempt to start a completed transaction (will ignore): " + tx); return false; } if (log.isDebugEnabled()) log.debug("Transaction started: " + tx); return true; }
/** * Handles prepare stage. * * @param tx Transaction to prepare. * @param entries Entries to lock or {@code null} if use default {@link IgniteInternalTx#optimisticLockEntries()}. * @throws IgniteCheckedException If preparation failed. */ public void prepareTx(IgniteInternalTx tx, @Nullable Collection<IgniteTxEntry> entries) throws IgniteCheckedException { if (tx.state() == MARKED_ROLLBACK) { if (tx.remainingTime() == -1) throw new IgniteTxTimeoutCheckedException("Transaction timed out: " + this); throw new IgniteCheckedException("Transaction is marked for rollback: " + tx); } // One-phase commit tx cannot timeout on prepare because it is expected to be committed. if (tx.remainingTime() == -1 && !tx.onePhaseCommit()) { tx.setRollbackOnly(); throw new IgniteTxTimeoutCheckedException("Transaction timed out: " + this); } if (tx.pessimistic() && tx.local()) return; // Nothing else to do in pessimistic mode. // Optimistic. assert tx.optimistic() || !tx.local(); if (!lockMultiple(tx, entries != null ? entries : tx.optimisticLockEntries())) { tx.setRollbackOnly(); throw new IgniteTxOptimisticCheckedException("Failed to prepare transaction (lock conflict): " + tx); } }