/** * Removes candidate from the list of near local candidates. * * @param cand Candidate to remove. */ public void removeExplicitLock(GridCacheMvccCandidate cand) { GridCacheExplicitLockSpan span = pendingExplicit.get(cand.threadId()); if (span == null) return; if (span.removeCandidate(cand)) pendingExplicit.remove(cand.threadId(), span); }
/** * 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; }
/** * Near local candidate. * * @param nodeId Node ID. * @param threadId Thread ID. * @return Remote candidate. */ @Nullable public GridCacheMvccCandidate localCandidate(UUID nodeId, long threadId) { if (locs != null) for (GridCacheMvccCandidate c : locs) if (c.nodeId().equals(nodeId) && c.threadId() == threadId) return c; return null; }
/** * @param nodeId Node ID. * @param threadId Thread ID. * @return Remote candidate. */ @Nullable GridCacheMvccCandidate remoteCandidate(UUID nodeId, long threadId) { if (rmts != null) for (GridCacheMvccCandidate c : rmts) if (c.nodeId().equals(nodeId) && c.threadId() == threadId) return c; return null; }
/** * @param threadId Thread ID. * @param reentry Reentry flag. * @return Local candidate for the thread. */ @Nullable private GridCacheMvccCandidate localCandidate(long threadId, boolean reentry) { if (locs != null) for (GridCacheMvccCandidate cand : locs) { if (cand.threadId() == threadId) { if (cand.reentry() && !reentry) continue; return cand; } } return null; }
/** * @param lockVer Lock ID. * @param threadId Thread ID. * @return {@code True} if locked by lock ID or thread ID. */ boolean isLocallyOwnedByIdOrThread(GridCacheVersion lockVer, long threadId) { CacheLockCandidates owners = localOwners(); if (owners != null) { for (int i = 0; i < owners.size(); i++) { GridCacheMvccCandidate owner = owners.candidate(i); if ((owner.version().equals(lockVer) || owner.threadId() == threadId)) return true; } } return false; }
/** * Removes explicit lock for given thread id, key and optional version. * * @param threadId Thread id. * @param key Key. * @param ver Optional version. * @return Candidate. */ public GridCacheMvccCandidate removeExplicitLock( long threadId, KeyCacheObject key, @Nullable GridCacheVersion ver) { assert threadId > 0; GridCacheExplicitLockSpan span = pendingExplicit.get(threadId); if (span == null) return null; GridCacheMvccCandidate cand = span.removeCandidate(key, ver); if (cand != null && span.isEmpty()) pendingExplicit.remove(cand.threadId(), span); return cand; }
/** * @param threadId Thread ID to check. * @param exclude Versions to ignore. * @return {@code True} if lock is owned by the thread with given ID. */ boolean isLocallyOwnedByThread(long threadId, boolean allowDhtLoc, GridCacheVersion... exclude) { CacheLockCandidates owners = localOwners(); if (owners != null) { for (int i = 0; i < owners.size(); i++) { GridCacheMvccCandidate owner = owners.candidate(i); if (owner.threadId() == threadId && owner.nodeId().equals(cctx.nodeId()) && (allowDhtLoc || !owner.dhtLocal()) && !U.containsObjectArray(exclude, owner.version())) return true; } } return false; }
/** * Adds candidate to the list of near local candidates. * * @param threadId Thread ID. * @param cand Candidate to add. * @param topVer Topology version. */ public void addExplicitLock( long threadId, GridCacheMvccCandidate cand, AffinityTopologyVersion topVer) { while (true) { GridCacheExplicitLockSpan span = pendingExplicit.get(cand.threadId()); if (span == null) { span = new GridCacheExplicitLockSpan(topVer, cand); GridCacheExplicitLockSpan old = pendingExplicit.putIfAbsent(threadId, span); if (old == null) break; else span = old; } // Either span was not empty, or concurrent put did not succeed. if (span.addCandidate(topVer, cand)) break; else pendingExplicit.remove(threadId, span); } }
/** * @param parent Parent entry. * @param nearNodeId Near node ID. * @param nearVer Near version. * @param threadId Thread ID. * @param ver Lock version. * @param timeout Lock acquisition timeout. * @param serOrder Version for serializable transactions ordering. * @param reenter Reentry flag ({@code true} if reentry is allowed). * @param tx Transaction flag. * @param implicitSingle Implicit flag. * @param dhtLoc DHT local flag. * @param read Read lock flag. * @return New lock candidate if lock was added, or current owner if lock was reentered, or * <tt>null</tt> if lock was owned by another thread and timeout is negative. */ @Nullable public GridCacheMvccCandidate addLocal( GridCacheEntryEx parent, @Nullable UUID nearNodeId, @Nullable GridCacheVersion nearVer, long threadId, GridCacheVersion ver, long timeout, @Nullable GridCacheVersion serOrder, boolean reenter, boolean tx, boolean implicitSingle, boolean dhtLoc, boolean read) { if (log.isDebugEnabled()) log.debug( "Adding local candidate [mvcc=" + this + ", parent=" + parent + ", threadId=" + threadId + ", ver=" + ver + ", timeout=" + timeout + ", reenter=" + reenter + ", tx=" + tx + "]"); // Don't check reenter for DHT candidates. if (!dhtLoc && !reenter) { GridCacheMvccCandidate owner = localOwner(); if (owner != null && owner.threadId() == threadId) return null; } // If there are pending locks and timeout is negative, // then we give up right away. if (timeout < 0) { if (locs != null || rmts != null) { GridCacheMvccCandidate owner = localOwner(); // Only proceed if this is a re-entry. if (owner == null || owner.threadId() != threadId) return null; } } UUID locNodeId = cctx.nodeId(); // If this is a reentry, then reentry flag will be flipped within 'add0(..)' method. GridCacheMvccCandidate cand = new GridCacheMvccCandidate( parent, locNodeId, nearNodeId, nearVer, threadId, ver, /*local*/ true, /*reenter*/ false, tx, implicitSingle, /*near-local*/ false, dhtLoc, serOrder, read); if (serOrder == null) { boolean add = add0(cand); assert add : cand; } else { if (!add0(cand)) return null; } return cand; }
/** * @param cand Candidate to add. * @return {@code False} if failed to add candidate and transaction should be cancelled. */ private boolean add0(GridCacheMvccCandidate cand) { assert cand != null; // Local. if (cand.local()) { if (locs == null) locs = new LinkedList<>(); if (!cand.nearLocal()) { if (!locs.isEmpty()) { if (cand.serializable()) { Iterator<GridCacheMvccCandidate> it = locs.descendingIterator(); if (cand.read()) { while (it.hasNext()) { GridCacheMvccCandidate c = it.next(); if (!c.serializable()) return false; if (!c.read()) { if (compareSerializableVersion(c, cand)) break; else return false; } } } else { while (it.hasNext()) { GridCacheMvccCandidate c = it.next(); if (!c.serializable() || !compareSerializableVersion(c, cand)) return false; if (!c.read()) break; } } locs.addLast(cand); return true; } GridCacheMvccCandidate first = locs.getFirst(); if (first.owner()) { // If reentry, add at the beginning. Note that // no reentry happens for DHT-local candidates. if (!cand.dhtLocal() && first.threadId() == cand.threadId()) { assert !first.serializable(); cand.setOwner(); cand.setReady(); cand.setReentry(); locs.addFirst(cand); return true; } } // Iterate in reverse order. for (ListIterator<GridCacheMvccCandidate> it = locs.listIterator(locs.size()); it.hasPrevious(); ) { GridCacheMvccCandidate c = it.previous(); assert !c.version().equals(cand.version()) : "Versions can't match [existing=" + c + ", new=" + cand + ']'; // Add after the owner or serializable tx. if (c.owner() || c.serializable()) { // Threads are checked above. assert cand.dhtLocal() || c.threadId() != cand.threadId(); // Reposition. it.next(); it.add(cand); return true; } // If not the owner, add after the lesser version. if (c.version().isLess(cand.version())) { // Reposition. it.next(); it.add(cand); return true; } } } // Either list is empty or candidate is first. locs.addFirst(cand); } else // For near local candidates just add it to the end of list. locs.add(cand); } // Remote. else { assert !cand.serializable() && !cand.read() : cand; if (rmts == null) rmts = new LinkedList<>(); assert !cand.owner() || localOwners() == null : "Cannot have local and remote owners " + "at the same time [cand=" + cand + ", locs=" + locs + ", rmts=" + rmts + ']'; GridCacheMvccCandidate cur = candidate(rmts, cand.version()); // For existing candidates, we only care about owners and keys. if (cur != null) { if (cand.owner()) cur.setOwner(); return true; } // Either list is empty or candidate is last. rmts.add(cand); } return true; }