/** @param maps Mappings. */ void addEntryMapping(@Nullable Collection<GridDistributedTxMapping> maps) { if (!F.isEmpty(maps)) { for (GridDistributedTxMapping map : maps) { ClusterNode n = map.node(); GridDistributedTxMapping m = mappings.get(n.id()); if (m == null) { mappings.put(m = new GridDistributedTxMapping(n)); m.near(map.near()); if (map.explicitLock()) m.markExplicitLock(); } for (IgniteTxEntry entry : map.entries()) m.add(entry); } if (log.isDebugEnabled()) log.debug( "Added mappings to transaction [locId=" + cctx.localNodeId() + ", mappings=" + maps + ", tx=" + this + ']'); } }
/** * 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 + ']'); }
/** Initializes future. */ @SuppressWarnings("ForLoopReplaceableByForEach") void finish() { if (tx.onNeedCheckBackup()) { assert tx.onePhaseCommit(); checkBackup(); // If checkBackup is set, it means that primary node has crashed and we will not need to send // finish request to it, so we can mark future as initialized. markInitialized(); return; } try { if (tx.finish(commit) || (!commit && tx.state() == UNKNOWN)) { if ((tx.onePhaseCommit() && needFinishOnePhase()) || (!tx.onePhaseCommit() && mappings != null)) { if (mappings.single()) { GridDistributedTxMapping mapping = mappings.singleMapping(); if (mapping != null) finish(mapping); } else finish(mappings.mappings()); } markInitialized(); if (!isSync() && !isDone()) { boolean complete = true; synchronized (futs) { // Avoid collection copy and iterator creation. for (int i = 0; i < futs.size(); i++) { IgniteInternalFuture<IgniteInternalTx> f = futs.get(i); if (isMini(f) && !f.isDone()) { complete = false; break; } } } if (complete) onComplete(); } } else onDone(new IgniteCheckedException("Failed to commit transaction: " + CU.txString(tx))); } catch (Error | RuntimeException e) { onDone(e); throw e; } catch (IgniteCheckedException e) { onDone(e); } }
/** @param m Mapping. */ private void finish(GridDistributedTxMapping m) { ClusterNode n = m.node(); assert !m.empty(); GridNearTxFinishRequest req = new GridNearTxFinishRequest( futId, tx.xidVersion(), tx.threadId(), commit, tx.isInvalidate(), tx.system(), tx.ioPolicy(), tx.syncCommit(), tx.syncRollback(), m.explicitLock(), tx.storeEnabled(), tx.topologyVersion(), null, null, null, tx.size(), tx.subjectId(), tx.taskNameHash(), tx.activeCachesDeploymentEnabled()); // If this is the primary node for the keys. if (n.isLocal()) { req.miniId(IgniteUuid.randomUuid()); IgniteInternalFuture<IgniteInternalTx> fut = cctx.tm().txHandler().finish(n.id(), tx, req); // Add new future. if (fut != null) add(fut); } else { FinishMiniFuture fut = new FinishMiniFuture(m); req.miniId(fut.futureId()); add(fut); // Append new future. if (tx.pessimistic()) cctx.tm().beforeFinishRemote(n.id(), tx.threadId()); try { cctx.io().send(n, req, tx.ioPolicy()); // If we don't wait for result, then mark future as done. if (!isSync() && !m.explicitLock()) fut.onDone(); } catch (ClusterTopologyCheckedException e) { // Remove previous mapping. mappings.remove(m.node().id()); fut.onNodeLeft(n.id()); } catch (IgniteCheckedException e) { // Fail the whole thing. fut.onDone(e); } } }
/** * @param nodeId Node ID to mark with explicit lock. * @return {@code True} if mapping was found. */ public boolean markExplicit(UUID nodeId) { explicitLock = true; GridDistributedTxMapping m = mappings.get(nodeId); if (m != null) { m.markExplicitLock(); return true; } return false; }
/** * @param map Mapping. * @param entry Entry. */ void addSingleEntryMapping(GridDistributedTxMapping map, IgniteTxEntry entry) { ClusterNode n = map.node(); GridDistributedTxMapping m = new GridDistributedTxMapping(n); mappings.put(m); m.near(map.near()); if (map.explicitLock()) m.markExplicitLock(); m.add(entry); }
/** @param nodeId Undo mapping. */ @Override public boolean removeMapping(UUID nodeId) { if (mappings.remove(nodeId) != null) { if (log.isDebugEnabled()) log.debug("Removed mapping for node [nodeId=" + nodeId + ", tx=" + this + ']'); return true; } else { if (log.isDebugEnabled()) log.debug("Mapping for node was not found [nodeId=" + nodeId + ", tx=" + this + ']'); return false; } }
/** {@inheritDoc} */ @Override public void onRemap(AffinityTopologyVersion topVer) { assert cctx.kernalContext().clientNode(); mapped = false; nearLocallyMapped = false; colocatedLocallyMapped = false; txNodes = null; onePhaseCommit = false; nearMap.clear(); dhtMap.clear(); mappings.clear(); synchronized (this) { this.topVer = topVer; } }
/** @param commit Commit flag. */ private void finishOnePhase(boolean commit) { assert Thread.holdsLock(this); if (finishOnePhaseCalled) return; finishOnePhaseCalled = true; GridDistributedTxMapping locMapping = mappings.localMapping(); if (locMapping != null) { // No need to send messages as transaction was already committed on remote node. // Finish local mapping only as we need send commit message to backups. IgniteInternalFuture<IgniteInternalTx> fut = cctx.tm().txHandler().finishColocatedLocal(commit, tx); // Add new future. if (fut != null) add(fut); } }
/** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public boolean onNodeLeft(UUID nodeId) { boolean found = false; for (IgniteInternalFuture<?> fut : futures()) if (isMini(fut)) { MinFuture f = (MinFuture) fut; if (f.onNodeLeft(nodeId)) { // Remove previous mapping. mappings.remove(nodeId); found = true; } } return found; }
private void checkBackup() { GridDistributedTxMapping mapping = mappings.singleMapping(); if (mapping != null) { UUID nodeId = mapping.node().id(); Collection<UUID> backups = tx.transactionNodes().get(nodeId); if (!F.isEmpty(backups)) { assert backups.size() == 1; UUID backupId = F.first(backups); ClusterNode backup = cctx.discovery().node(backupId); // Nothing to do if backup has left the grid. if (backup == null) { readyNearMappingFromBackup(mapping); ClusterTopologyCheckedException cause = new ClusterTopologyCheckedException("Backup node left grid: " + backupId); cause.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion())); onDone( new IgniteTxRollbackCheckedException( "Failed to commit transaction " + "(backup has left grid): " + tx.xidVersion(), cause)); } else { final CheckBackupMiniFuture mini = new CheckBackupMiniFuture(backup, mapping); add(mini); if (backup.isLocal()) { boolean committed = !cctx.tm().addRolledbackTx(tx); readyNearMappingFromBackup(mapping); if (committed) { if (tx.syncCommit()) { GridCacheVersion nearXidVer = tx.nearXidVersion(); assert nearXidVer != null : tx; IgniteInternalFuture<?> fut = cctx.tm().remoteTxFinishFuture(nearXidVer); fut.listen( new CI1<IgniteInternalFuture<?>>() { @Override public void apply(IgniteInternalFuture<?> fut) { mini.onDone(tx); } }); return; } mini.onDone(tx); } else { ClusterTopologyCheckedException cause = new ClusterTopologyCheckedException("Primary node left grid: " + nodeId); cause.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion())); mini.onDone( new IgniteTxRollbackCheckedException( "Failed to commit transaction " + "(transaction has been rolled back on backup node): " + tx.xidVersion(), cause)); } } else { GridDhtTxFinishRequest finishReq = checkCommittedRequest(mini.futureId()); // Preserve old behavior, otherwise response is not sent. if (WAIT_REMOTE_TXS_SINCE.compareTo(backup.version()) > 0) finishReq.syncCommit(true); try { if (FINISH_NEAR_ONE_PHASE_SINCE.compareTo(backup.version()) <= 0) cctx.io().send(backup, finishReq, tx.ioPolicy()); else { mini.onDone( new IgniteTxHeuristicCheckedException( "Failed to check for tx commit on " + "the backup node (node has an old Ignite version) [rmtNodeId=" + backup.id() + ", ver=" + backup.version() + ']')); } } catch (ClusterTopologyCheckedException e) { mini.onNodeLeft(backupId); } catch (IgniteCheckedException e) { mini.onDone(e); } } } } else readyNearMappingFromBackup(mapping); } }