@Override public GridCacheVersion apply(IgniteInternalTx tx) { return tx.xidVersion(); }
/** * @param tx Committed transaction. * @return If transaction was not already present in completed set. */ public boolean addRolledbackTx(IgniteInternalTx tx) { return addRolledbackTx(tx, tx.xidVersion()); }
/** {@inheritDoc} */ @Override public String toString() { return GridToStringBuilder.toString(IgniteTxEntry.class, this, "xidVer", tx == null ? "null" : tx.xidVersion()); } }
/** * Gets version of transaction in tx context or {@code null} * if tx context is empty. * <p> * This is a convenience method provided mostly for debugging. * * @return Transaction version from transaction context. */ @Nullable public GridCacheVersion txContextVersion() { IgniteInternalTx tx = txContext(); return tx == null ? null : tx.xidVersion(); }
/** {@inheritDoc} */ @Override public void txUnlock(IgniteInternalTx tx) throws GridCacheEntryRemovedException { removeLock(tx.xidVersion()); }
/** * @param tx Tx to remove. */ public void removeCommittedTx(IgniteInternalTx tx) { completedVersHashMap.remove(tx.xidVersion(), true); if (tx.needsCompletedVersions()) completedVersSorted.remove(tx.xidVersion(), true); }
/** * @param tx Committed transaction. */ public void addCommittedTx(IgniteInternalTx tx) { addCommittedTx(tx, tx.xidVersion(), tx.nearXidVersion()); }
/** {@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."); }
/** * @param tx Transaction. * @param txNum Expected number of transactions on remote node. * @param nearTxCheck {@code True} if should check only tx on near node. * @param futId Future ID. * @param miniId Mini future ID. * @param addDepInfo Deployment info flag. */ public GridCacheTxRecoveryRequest(IgniteInternalTx tx, int txNum, boolean nearTxCheck, IgniteUuid futId, IgniteUuid miniId, boolean addDepInfo) { super(tx.xidVersion(), 0, addDepInfo); nearXidVer = tx.nearXidVersion(); sys = tx.system(); this.futId = futId; this.miniId = miniId; this.txNum = txNum; this.nearTxCheck = nearTxCheck; }
/** {@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(); } }
/** * 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); } }
/** {@inheritDoc} */ @Override public boolean tmLock(IgniteInternalTx tx, long timeout, @Nullable GridCacheVersion serOrder, GridCacheVersion serReadVer, boolean read) throws GridCacheEntryRemovedException { GridCacheMvccCandidate cand = addLocal( tx.threadId(), tx.xidVersion(), serOrder, serReadVer, timeout, /*reenter*/false, /*tx*/true, tx.implicitSingle(), read ); if (cand != null) { readyLocal(cand); return true; } return false; }
/** * * @param tx Transaction to check. * @return {@code True} if transaction has been committed or rolled back, * {@code false} otherwise. */ private boolean isCompleted(IgniteInternalTx tx) { boolean completed = completedVersHashMap.containsKey(tx.xidVersion()); // Need check that for tx rollback message was not received before lock. // This could happen on timeout or async rollback. if (!completed && tx.local() && tx.dht()) return completedVersHashMap.containsKey(tx.nearXidVersion()); return completed; }
/** * @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() : "") + ']'; }
/** * 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; }
/** * @param tx Transaction. */ private void processCompletedEntries(IgniteInternalTx tx) { if (tx.needsCompletedVersions()) { GridCacheVersion min = minVersion(tx.readEntries(), tx.xidVersion(), tx); min = minVersion(tx.writeEntries(), min, tx); assert min != null; IgnitePair<Collection<GridCacheVersion>> versPair = versions(min); tx.completedVersions(min, versPair.get1(), versPair.get2()); } }
/** * Commits or rolls back prepared transaction. * * @param tx Transaction. * @param commit Whether transaction should be committed or rolled back. */ public void finishTxOnRecovery(final IgniteInternalTx tx, boolean commit) { if (log.isInfoEnabled()) log.info("Finishing prepared transaction [commit=" + commit + ", tx=" + tx + ']'); if (!tx.markFinalizing(RECOVERY_FINISH)) { if (log.isInfoEnabled()) log.info("Will not try to commit prepared transaction (could not mark finalized): " + tx); return; } if (tx instanceof IgniteTxRemoteEx) { IgniteTxRemoteEx rmtTx = (IgniteTxRemoteEx)tx; rmtTx.doneRemote(tx.xidVersion(), Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList()); } if (commit) tx.commitAsync().listen(new CommitListener(tx)); else if (tx.mvccSnapshot() != null && !tx.local()) // remote (backup) mvcc transaction sends partition counters to other backup transaction // in order to keep counters consistent neighborcastPartitionCountersAndRollback(tx); else tx.rollbackAsync(); }
/** * Go through all candidates for entries involved in transaction and find their min * version. We know that these candidates will commit after this transaction, and * therefore we can grab the min version so we can send all committed and rolled * back versions from min to current to remote nodes for re-ordering. * * @param entries Entries. * @param min Min version so far. * @param tx Transaction. * @return Minimal available version. */ private GridCacheVersion minVersion(Iterable<IgniteTxEntry> entries, GridCacheVersion min, IgniteInternalTx tx) { for (IgniteTxEntry txEntry : entries) { GridCacheEntryEx cached = txEntry.cached(); // We are assuming that this method is only called on commit. In that // case, if lock is held, entry can never be removed. assert txEntry.isRead() || !cached.obsolete(tx.xidVersion()) : "Invalid obsolete version for transaction [entry=" + cached + ", tx=" + tx + ']'; for (GridCacheMvccCandidate cand : cached.remoteMvccSnapshot()) if (min == null || cand.version().isLess(min)) min = cand.version(); } return min; }
/** * @param tx Transaction. */ private void removeObsolete(IgniteInternalTx tx) { Collection<IgniteTxEntry> entries = tx.local() ? tx.allEntries() : tx.writeEntries(); for (IgniteTxEntry entry : entries) { GridCacheEntryEx cached = entry.cached(); GridCacheContext cacheCtx = entry.context(); if (cached == null) cached = cacheCtx.cache().peekEx(entry.key()); if (cached.detached()) continue; try { if (cached.obsolete() || cached.markObsoleteIfEmpty(tx.xidVersion())) cacheCtx.cache().removeEntry(cached); if (!tx.near() && isNearEnabled(cacheCtx)) { GridNearCacheAdapter near = cacheCtx.isNear() ? cacheCtx.near() : cacheCtx.dht().near(); GridNearCacheEntry e = near.peekExx(entry.key()); if (e != null && e.markObsoleteIfEmpty(null)) near.removeEntry(e); } } catch (IgniteCheckedException e) { U.error(log, "Failed to remove obsolete entry from cache: " + cached, e); } } }