/** * For all remote candidates standing behind the candidate being salvaged marks their transactions * as system invalidate and marks these candidates as owned and used. * * @param ver Version to salvage. */ public void salvageRemote(GridCacheVersion ver) { assert ver != null; GridCacheMvccCandidate cand = candidate(rmts, ver); if (cand != null) { assert rmts != null; assert !rmts.isEmpty(); for (Iterator<GridCacheMvccCandidate> iter = rmts.iterator(); iter.hasNext(); ) { GridCacheMvccCandidate rmt = iter.next(); // For salvaged candidate doneRemote will be called explicitly. if (rmt == cand) break; // Only Near and DHT remote candidates should be released. assert !rmt.nearLocal(); IgniteInternalTx tx = cctx.tm().tx(rmt.version()); if (tx != null) { tx.systemInvalidate(true); rmt.setOwner(); rmt.setUsed(); } else iter.remove(); } } }
/** * Local release. * * @param threadId ID of the thread. * @return Removed candidate. */ @Nullable public GridCacheMvccCandidate releaseLocal(long threadId) { CacheLockCandidates owners = localOwners(); // Release had no effect. if (owners == null) return null; GridCacheMvccCandidate owner = null; for (int i = 0; i < owners.size(); i++) { GridCacheMvccCandidate owner0 = owners.candidate(i); if (owner0.threadId() == threadId) { owner = owner0; break; } } if (owner != null) { owner.setUsed(); remove0(owner.version(), true); return owner; } else return null; }
/** * Removes all candidates for node. * * @param nodeId Node ID. * @return Current owner. */ @Nullable public CacheLockCandidates removeExplicitNodeCandidates(UUID nodeId) { if (rmts != null) { for (Iterator<GridCacheMvccCandidate> it = rmts.iterator(); it.hasNext(); ) { GridCacheMvccCandidate cand = it.next(); if (!cand.tx() && (nodeId.equals(cand.nodeId()) || nodeId.equals(cand.otherNodeId()))) { cand.setUsed(); // Mark as used to be consistent. cand.setRemoved(); it.remove(); } } if (rmts.isEmpty()) rmts = null; } if (locs != null) { for (Iterator<GridCacheMvccCandidate> it = locs.iterator(); it.hasNext(); ) { GridCacheMvccCandidate cand = it.next(); if (!cand.tx() && nodeId.equals(cand.otherNodeId()) && cand.dhtLocal()) { cand.setUsed(); // Mark as used to be consistent. cand.setRemoved(); it.remove(); } } if (locs.isEmpty()) locs = null; } reassign(); return allOwners(); }
/** * Sets remote candidate to done. * * @param ver Version. * @param pending Pending versions. * @param committed Committed versions. * @param rolledback Rolledback versions. * @return Lock owner. */ @Nullable public CacheLockCandidates doneRemote( GridCacheVersion ver, Collection<GridCacheVersion> pending, Collection<GridCacheVersion> committed, Collection<GridCacheVersion> rolledback) { assert ver != null; if (log.isDebugEnabled()) log.debug("Setting remote candidate to done [mvcc=" + this + ", ver=" + ver + "]"); // Check remote candidate. GridCacheMvccCandidate cand = candidate(rmts, ver); if (cand != null) { assert rmts != null; assert !rmts.isEmpty(); assert !cand.local() : "Remote candidate is marked as local: " + cand; assert !cand.nearLocal() : "Remote candidate is marked as near local: " + cand; cand.setOwner(); cand.setUsed(); List<GridCacheMvccCandidate> mvAfter = null; for (ListIterator<GridCacheMvccCandidate> it = rmts.listIterator(); it.hasNext(); ) { GridCacheMvccCandidate c = it.next(); assert !c.nearLocal() : "Remote candidate marked as near local: " + c; if (c == cand) { if (mvAfter != null) for (GridCacheMvccCandidate mv : mvAfter) it.add(mv); break; } else if (!committed.contains(c.version()) && !rolledback.contains(c.version()) && pending.contains(c.version())) { it.remove(); if (mvAfter == null) mvAfter = new LinkedList<>(); mvAfter.add(c); } } } return allOwners(); }
/** * Removes candidate from collection. * * @param col Collection. * @param ver Version of the candidate to remove. * @return {@code True} if candidate was removed. */ private boolean remove0(Collection<GridCacheMvccCandidate> col, GridCacheVersion ver) { if (col != null) { for (Iterator<GridCacheMvccCandidate> it = col.iterator(); it.hasNext(); ) { GridCacheMvccCandidate cand = it.next(); if (cand.version().equals(ver)) { cand.setUsed(); cand.setRemoved(); it.remove(); reassign(); return true; } } } return false; }
/** * Moves completed candidates right before the base one. Note that if base is not found, then * nothing happens and {@code false} is returned. * * @param baseVer Base version. * @param committedVers Committed versions relative to base. * @param rolledbackVers Rolled back versions relative to base. */ public void orderCompleted( GridCacheVersion baseVer, Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers) { assert baseVer != null; if (rmts != null && !F.isEmpty(committedVers)) { Deque<GridCacheMvccCandidate> mvAfter = null; int maxIdx = -1; for (ListIterator<GridCacheMvccCandidate> it = rmts.listIterator(rmts.size()); it.hasPrevious(); ) { GridCacheMvccCandidate cur = it.previous(); if (!cur.version().equals(baseVer) && committedVers.contains(cur.version())) { cur.setOwner(); assert localOwners() == null || localOwner().nearLocal() : "Cannot not have local owner and " + "remote completed transactions at the same time [baseVer=" + baseVer + ", committedVers=" + committedVers + ", rolledbackVers=" + rolledbackVers + ", localOwner=" + localOwner() + ", locs=" + locs + ", rmts=" + rmts + ']'; if (maxIdx < 0) maxIdx = it.nextIndex(); } else if (maxIdx >= 0 && cur.version().isGreaterEqual(baseVer)) { if (--maxIdx >= 0) { if (mvAfter == null) mvAfter = new LinkedList<>(); it.remove(); mvAfter.addFirst(cur); } } // If base is completed, then set it to owner too. if (!cur.owner() && cur.version().equals(baseVer) && committedVers.contains(cur.version())) cur.setOwner(); } if (maxIdx >= 0 && mvAfter != null) { ListIterator<GridCacheMvccCandidate> it = rmts.listIterator(maxIdx + 1); for (GridCacheMvccCandidate cand : mvAfter) it.add(cand); } // Remove rolled back versions. if (!F.isEmpty(rolledbackVers)) { for (Iterator<GridCacheMvccCandidate> it = rmts.iterator(); it.hasNext(); ) { GridCacheMvccCandidate cand = it.next(); if (rolledbackVers.contains(cand.version())) { cand.setUsed(); // Mark as used to be consistent, even though we are about to remove it. it.remove(); } } if (rmts.isEmpty()) rmts = null; } } }