/** {@inheritDoc} */ @SuppressWarnings({"unchecked"}) @Override public void onOwnerChanged( GridCacheEntryEx entry, GridCacheMvccCandidate prev, GridCacheMvccCandidate owner) { assert entry != null; assert owner != prev : "New and previous owner are identical instances: " + owner; assert owner == null || prev == null || !owner.version().equals(prev.version()) : "New and previous owners have identical versions [owner=" + owner + ", prev=" + prev + ']'; if (log.isDebugEnabled()) log.debug( "Received owner changed callback [" + entry.key() + ", owner=" + owner + ", prev=" + prev + ']'); if (owner != null && (owner.local() || owner.nearLocal())) { Collection<? extends GridCacheFuture> futCol = futs.get(owner.version()); if (futCol != null) { for (GridCacheFuture fut : futCol) { if (fut instanceof GridCacheMvccFuture && !fut.isDone()) { GridCacheMvccFuture<Boolean> mvccFut = (GridCacheMvccFuture<Boolean>) fut; // Since this method is called outside of entry synchronization, // we can safely invoke any method on the future. // Also note that we don't remove future here if it is done. // The removal is initiated from within future itself. if (mvccFut.onOwnerChanged(entry, owner)) return; } } } } if (log.isDebugEnabled()) log.debug( "Lock future not found for owner change callback (will try transaction futures) [owner=" + owner + ", prev=" + prev + ", entry=" + entry + ']'); // If no future was found, delegate to transaction manager. if (cctx.tm().onOwnerChanged(entry, owner)) { if (log.isDebugEnabled()) log.debug("Found transaction for changed owner: " + owner); } else if (log.isDebugEnabled()) log.debug("Failed to find transaction for changed owner: " + owner); for (FinishLockFuture f : finishFuts) f.recheck(entry); }
/** * @param cand Local candidate added in any of the {@code addLocal(..)} methods. * @return Current lock owner. */ @Nullable public CacheLockCandidates readyLocal(GridCacheMvccCandidate cand) { assert cand.local(); cand.setReady(); reassign(); return allOwners(); }
/** * @param ver Lock version to acquire or set to ready. * @return Current owner. */ @Nullable public CacheLockCandidates readyLocal(GridCacheVersion ver) { GridCacheMvccCandidate cand = candidate(ver); if (cand == null) return allOwners(); assert cand.local(); return readyLocal(cand); }
/** @param cand Remote candidate. */ private void addRemote(GridCacheMvccCandidate cand) { assert !cand.local(); if (log.isDebugEnabled()) log.debug("Adding remote candidate [mvcc=" + this + ", cand=" + cand + "]"); cctx.versions().onReceived(cand.nodeId(), cand.version()); add0(cand); }
/** * @param cand Local candidate to remove. * @return {@code True} if removed. */ public boolean removeLocal(GridCacheMvccCandidate cand) { assert cand.key() != null; assert cand.local(); if (cand.dhtLocal() && dhtLocCands.remove(cand)) { if (log.isDebugEnabled()) log.debug("Removed local candidate: " + cand); return true; } return false; }
/** * 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(); }
/** * @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; }