/** * @param cand Existing candidate. * @param newCand New candidate. * @return {@code False} if new candidate can not be added. */ private boolean compareSerializableVersion( GridCacheMvccCandidate cand, GridCacheMvccCandidate newCand) { assert cand.serializable() && newCand.serializable(); GridCacheVersion candOrder = cand.serializableOrder(); assert candOrder != null : cand; GridCacheVersion newCandOrder = newCand.serializableOrder(); assert newCandOrder != null : newCand; int cmp = SER_VER_COMPARATOR.compare(candOrder, newCandOrder); assert cmp != 0; return cmp < 0; }
/** Assigns local lock. */ private void reassign() { GridCacheMvccCandidate firstRmt = null; if (rmts != null) { for (GridCacheMvccCandidate cand : rmts) { if (firstRmt == null) firstRmt = cand; // If there is a remote owner, then local cannot be an owner, // so no reassignment happens. if (cand.owner()) return; } } if (locs != null) { boolean first = true; ListIterator<GridCacheMvccCandidate> it = locs.listIterator(); while (it.hasNext()) { GridCacheMvccCandidate cand = it.next(); if (first) { if (cand.read()) { if (cand.ready() && !cand.owner()) cand.setOwner(); while (it.hasNext()) { cand = it.next(); if (!cand.read()) break; if (cand.ready() && !cand.owner()) cand.setOwner(); } return; } else if (cand.serializable()) { if (cand.owner() || !cand.ready()) return; cand.setOwner(); return; } first = false; } if (cand.owner()) return; if (cand.ready()) { GridCacheMvccCandidate prev = nonRollbackPrevious(cand); // If previous has not been acquired, this candidate cannot acquire lock either, // so we move on to the next one. if (prev != null && !prev.owner()) continue; boolean assigned = false; if (!cctx.isNear() && firstRmt != null && cand.version().isGreater(firstRmt.version())) { // Check previous candidates for 2 cases: // 1. If this candidate is waiting for a smaller remote version, // then we must check if previous candidate is the owner and // has the same remote candidate version. In that case, we can // safely set this candidate to owner as well. // 2. If this candidate is waiting for a smaller remote version, // then we must check if previous candidate is the owner and // any of the local candidates with versions smaller than first // remote version have the same key as the previous owner. In // that case, we can safely set this candidate to owner as well. while (prev != null && prev.owner()) { for (GridCacheMvccCandidate c : prev.parent().remoteMvccSnapshot()) { if (c.version().equals(firstRmt.version())) { cand.setOwner(); assigned = true; break; // For. } } if (!assigned) { for (GridCacheMvccCandidate c : locs) { if (c == cand || c.version().isGreater(firstRmt.version())) break; for (GridCacheMvccCandidate p = c.previous(); p != null; p = p.previous()) { if (p.key().equals(prev.key())) { cand.setOwner(); assigned = true; break; // For. } } if (assigned) break; // For. } } if (assigned) break; // While. prev = prev.previous(); } } if (!assigned) { if (!cctx.isNear() && firstRmt != null) { if (cand.version().isLess(firstRmt.version())) { assert !cand.nearLocal(); cand.setOwner(); assigned = true; } } else { cand.setOwner(); assigned = true; } } if (assigned) { assert !cand.serializable() : cand; it.remove(); // Owner must be first in the list. locs.addFirst(cand); } return; } } } }
/** * @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; }