/** * Adds key mapping to dht mapping. * * @param key Key to add. * @param node Node this key mapped to. */ public void addKeyMapping(IgniteTxKey key, ClusterNode node) { GridDistributedTxMapping m = mappings.get(node.id()); if (m == null) mappings.put(m = new GridDistributedTxMapping(node)); IgniteTxEntry txEntry = entry(key); assert txEntry != null; txEntry.nodeId(node.id()); m.add(txEntry); if (log.isDebugEnabled()) log.debug( "Added mappings to transaction [locId=" + cctx.localNodeId() + ", key=" + key + ", node=" + node + ", tx=" + this + ']'); }
/** * Adds entries to started near remote tx. * * @param ldr Class loader. * @param entries Entries to add. * @throws IgniteCheckedException If failed. */ public void addEntries(ClassLoader ldr, Iterable<IgniteTxEntry> entries) throws IgniteCheckedException { for (IgniteTxEntry entry : entries) { entry.unmarshal(cctx, true, ldr); addEntry(entry); } }
/** * This constructor is meant for optimistic transactions. * * @param ldr Class loader. * @param nodeId Node ID. * @param nearNodeId Near node ID. * @param rmtThreadId Remote thread ID. * @param xidVer XID version. * @param commitVer Commit version. * @param sys System flag. * @param concurrency Concurrency level (should be pessimistic). * @param isolation Transaction isolation. * @param invalidate Invalidate flag. * @param timeout Timeout. * @param writeEntries Write entries. * @param ctx Cache registry. * @param txSize Expected transaction size. * @throws IgniteCheckedException If unmarshalling failed. */ public GridNearTxRemote( GridCacheSharedContext ctx, ClassLoader ldr, UUID nodeId, UUID nearNodeId, long rmtThreadId, GridCacheVersion xidVer, GridCacheVersion commitVer, boolean sys, byte plc, TransactionConcurrency concurrency, TransactionIsolation isolation, boolean invalidate, long timeout, Collection<IgniteTxEntry> writeEntries, int txSize, @Nullable UUID subjId, int taskNameHash) throws IgniteCheckedException { super( ctx, nodeId, rmtThreadId, xidVer, commitVer, sys, plc, concurrency, isolation, invalidate, timeout, txSize, subjId, taskNameHash); assert nearNodeId != null; this.nearNodeId = nearNodeId; readMap = Collections.emptyMap(); writeMap = new LinkedHashMap<>( writeEntries != null ? Math.max(txSize, writeEntries.size()) : txSize, 1.0f); if (writeEntries != null) { for (IgniteTxEntry entry : writeEntries) { entry.unmarshal(ctx, true, ldr); addEntry(entry); } } }
/** {@inheritDoc} */ @Override protected GridCacheEntryEx entryEx(GridCacheContext cacheCtx, IgniteTxKey key) { if (cacheCtx.isColocated()) { IgniteTxEntry txEntry = entry(key); if (txEntry == null) return cacheCtx.colocated().entryExx(key.key(), topologyVersion(), true); GridCacheEntryEx cached = txEntry.cached(); assert cached != null; if (cached.detached()) return cached; if (cached.obsoleteVersion() != null) { cached = cacheCtx.colocated().entryExx(key.key(), topologyVersion(), true); txEntry.cached(cached); } return cached; } else return cacheCtx.cache().entryEx(key.key()); }
/** {@inheritDoc} */ @Override protected void updateExplicitVersion(IgniteTxEntry txEntry, GridCacheEntryEx entry) throws GridCacheEntryRemovedException { if (entry.detached()) { GridCacheMvccCandidate cand = cctx.mvcc().explicitLock(threadId(), entry.txKey()); if (cand != null && !xidVersion().equals(cand.version())) { GridCacheVersion candVer = cand.version(); txEntry.explicitVersion(candVer); if (candVer.isLess(minVer)) minVer = candVer; } } else super.updateExplicitVersion(txEntry, entry); }
/** * @param entry Entry to enlist. * @throws IgniteCheckedException If failed. * @return {@code True} if entry was enlisted. */ private boolean addEntry(IgniteTxEntry entry) throws IgniteCheckedException { checkInternal(entry.txKey()); GridCacheContext cacheCtx = entry.context(); if (!cacheCtx.isNear()) cacheCtx = cacheCtx.dht().near().context(); GridNearCacheEntry cached = cacheCtx.near().peekExx(entry.key()); if (cached == null) { evicted.add(entry.txKey()); return false; } else { try { cached.unswap(); CacheObject val = cached.peek(true, false, false, null); if (val == null && cached.evictInternal(false, xidVer, null)) { evicted.add(entry.txKey()); return false; } else { // Initialize cache entry. entry.cached(cached); txState.addWriteEntry(entry.txKey(), entry); addExplicit(entry); return true; } } catch (GridCacheEntryRemovedException ignore) { evicted.add(entry.txKey()); if (log.isDebugEnabled()) log.debug("Got removed entry when adding to remote transaction (will ignore): " + cached); return false; } } }
/** * @param entries Entries. * @param dhtVer DHT version. * @param pendingVers Pending versions. * @param committedVers Committed versions. * @param rolledbackVers Rolled back versions. */ void readyNearLocks( Collection<IgniteTxEntry> entries, GridCacheVersion dhtVer, Collection<GridCacheVersion> pendingVers, Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers) { for (IgniteTxEntry txEntry : entries) { while (true) { GridCacheContext cacheCtx = txEntry.cached().context(); assert cacheCtx.isNear(); GridDistributedCacheEntry entry = (GridDistributedCacheEntry) txEntry.cached(); try { // Handle explicit locks. GridCacheVersion explicit = txEntry.explicitVersion(); if (explicit == null) { entry.readyNearLock(xidVer, dhtVer, committedVers, rolledbackVers, pendingVers); } break; } catch (GridCacheEntryRemovedException ignored) { assert entry.obsoleteVersion() != null; if (log.isDebugEnabled()) log.debug( "Replacing obsolete entry in remote transaction [entry=" + entry + ", tx=" + this + ']'); // Replace the entry. txEntry.cached(txEntry.context().cache().entryEx(txEntry.key())); } } } }
/** {@inheritDoc} */ @Override public boolean onDone(IgniteInternalTx tx0, Throwable err) { if (isDone()) return false; synchronized (this) { if (isDone()) return false; if (err != null) { tx.commitError(err); boolean marked = tx.setRollbackOnly(); if (err instanceof IgniteTxRollbackCheckedException) { if (marked) { try { tx.rollback(); } catch (IgniteCheckedException ex) { U.error(log, "Failed to automatically rollback transaction: " + tx, ex); } } } else if (tx.implicit() && tx.isSystemInvalidate()) { // Finish implicit transaction on heuristic error. try { tx.close(); } catch (IgniteCheckedException ex) { U.error(log, "Failed to invalidate transaction: " + tx, ex); } } } if (initialized() || err != null) { if (tx.needCheckBackup()) { assert tx.onePhaseCommit(); if (err != null) err = new TransactionRollbackException("Failed to commit transaction.", err); try { tx.finish(err == null); } catch (IgniteCheckedException e) { if (err != null) err.addSuppressed(e); else err = e; } } if (tx.onePhaseCommit()) { boolean commit = this.commit && err == null; finishOnePhase(commit); tx.tmFinish(commit); } if (super.onDone(tx0, err)) { if (error() instanceof IgniteTxHeuristicCheckedException) { AffinityTopologyVersion topVer = tx.topologyVersion(); for (IgniteTxEntry e : tx.writeMap().values()) { GridCacheContext cacheCtx = e.context(); try { if (e.op() != NOOP && !cacheCtx.affinity().localNode(e.key(), topVer)) { GridCacheEntryEx entry = cacheCtx.cache().peekEx(e.key()); if (entry != null) entry.invalidate(null, tx.xidVersion()); } } catch (Throwable t) { U.error(log, "Failed to invalidate entry.", t); if (t instanceof Error) throw (Error) t; } } } // Don't forget to clean up. cctx.mvcc().removeFuture(futId); return true; } } } return false; }
/** * @param dhtMap DHT map. * @param nearMap Near map. * @return {@code True} in case there is at least one synchronous {@code MiniFuture} to wait for. */ private boolean finish( Map<UUID, GridDistributedTxMapping> dhtMap, Map<UUID, GridDistributedTxMapping> nearMap) { if (tx.onePhaseCommit()) return false; boolean sync = tx.syncMode() == FULL_SYNC; if (tx.explicitLock()) sync = true; boolean res = false; // Create mini futures. for (GridDistributedTxMapping dhtMapping : dhtMap.values()) { ClusterNode n = dhtMapping.node(); assert !n.isLocal(); GridDistributedTxMapping nearMapping = nearMap.get(n.id()); if (dhtMapping.empty() && nearMapping != null && nearMapping.empty()) // Nothing to send. continue; MiniFuture fut = new MiniFuture(dhtMapping, nearMapping); add(fut); // Append new future. Collection<Long> updCntrs = new ArrayList<>(dhtMapping.entries().size()); for (IgniteTxEntry e : dhtMapping.entries()) updCntrs.add(e.updateCounter()); GridDhtTxFinishRequest req = new GridDhtTxFinishRequest( tx.nearNodeId(), futId, fut.futureId(), tx.topologyVersion(), tx.xidVersion(), tx.commitVersion(), tx.threadId(), tx.isolation(), commit, tx.isInvalidate(), tx.system(), tx.ioPolicy(), tx.isSystemInvalidate(), sync, sync, tx.completedBase(), tx.committedVersions(), tx.rolledbackVersions(), tx.pendingVersions(), tx.size(), tx.subjectId(), tx.taskNameHash(), tx.activeCachesDeploymentEnabled(), updCntrs, false, false); req.writeVersion(tx.writeVersion() != null ? tx.writeVersion() : tx.xidVersion()); try { cctx.io().send(n, req, tx.ioPolicy()); if (msgLog.isDebugEnabled()) { msgLog.debug( "DHT finish fut, sent request dht [txId=" + tx.nearXidVersion() + ", dhtTxId=" + tx.xidVersion() + ", node=" + n.id() + ']'); } if (sync) res = true; else fut.onDone(); } catch (IgniteCheckedException e) { // Fail the whole thing. if (e instanceof ClusterTopologyCheckedException) fut.onNodeLeft((ClusterTopologyCheckedException) e); else { if (msgLog.isDebugEnabled()) { msgLog.debug( "DHT finish fut, failed to send request dht [txId=" + tx.nearXidVersion() + ", dhtTxId=" + tx.xidVersion() + ", node=" + n.id() + ", err=" + e + ']'); } fut.onResult(e); } } } for (GridDistributedTxMapping nearMapping : nearMap.values()) { if (!dhtMap.containsKey(nearMapping.node().id())) { if (nearMapping.empty()) // Nothing to send. continue; MiniFuture fut = new MiniFuture(null, nearMapping); add(fut); // Append new future. GridDhtTxFinishRequest req = new GridDhtTxFinishRequest( tx.nearNodeId(), futId, fut.futureId(), tx.topologyVersion(), tx.xidVersion(), tx.commitVersion(), tx.threadId(), tx.isolation(), commit, tx.isInvalidate(), tx.system(), tx.ioPolicy(), tx.isSystemInvalidate(), sync, sync, tx.completedBase(), tx.committedVersions(), tx.rolledbackVersions(), tx.pendingVersions(), tx.size(), tx.subjectId(), tx.taskNameHash(), tx.activeCachesDeploymentEnabled(), false, false); req.writeVersion(tx.writeVersion()); try { cctx.io().send(nearMapping.node(), req, tx.ioPolicy()); if (msgLog.isDebugEnabled()) { msgLog.debug( "DHT finish fut, sent request near [txId=" + tx.nearXidVersion() + ", dhtTxId=" + tx.xidVersion() + ", node=" + nearMapping.node().id() + ']'); } if (sync) res = true; else fut.onDone(); } catch (IgniteCheckedException e) { // Fail the whole thing. if (e instanceof ClusterTopologyCheckedException) fut.onNodeLeft((ClusterTopologyCheckedException) e); else { if (msgLog.isDebugEnabled()) { msgLog.debug( "DHT finish fut, failed to send request near [txId=" + tx.nearXidVersion() + ", dhtTxId=" + tx.xidVersion() + ", node=" + nearMapping.node().id() + ", err=" + e + ']'); } fut.onResult(e); } } } } return res; }