/** * @param cand Candidate to check. * @return First predecessor that is owner or is not used. */ @Nullable private GridCacheMvccCandidate nonRollbackPrevious(GridCacheMvccCandidate cand) { for (GridCacheMvccCandidate c = cand.previous(); c != null; c = c.previous()) { if (c.owner() || !c.used()) return c; } return null; }
/** * @param cacheCtx Cache context. * @param cand Cache lock candidate to add. * @return {@code True} if added as a result of this operation, {@code false} if was previously * added. */ public boolean addNext(GridCacheContext cacheCtx, GridCacheMvccCandidate cand) { assert cand != null; assert !cand.reentry() : "Lock reentries should not be linked: " + cand; // Don't order near candidates by thread as they will be ordered on // DHT node. Also, if candidate is implicit, no point to order him. if (cacheCtx.isNear() || cand.singleImplicit()) return true; LinkedList<GridCacheMvccCandidate> queue = pending.get(); GridCacheMvccCandidate prev = null; if (!queue.isEmpty()) prev = queue.getLast(); queue.add(cand); if (prev != null) { prev.next(cand); cand.previous(prev); } if (log.isDebugEnabled()) log.debug("Linked new candidate: " + cand); return true; }
/** 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; } } } }