/** * Collects all dependent nodes of root node and locks them. * * @param rootNode root node to lookup dependencies from * @return a list of dependent caches and a super lock for this list. Note: returned super lock is * <b>already locked</b> unless there was an exception thrown. */ public static RecursiveLock lockRecursive(DependencyNode rootNode) { TIdentityHashSet<CleaningNode> elements = DependencyTracker.getAllDependentNodes(Collections.singleton(rootNode)); Iterable<DependencyNode> nodes = nodeMapping(elements); while (true) { SuperLock superLock = getSuperLock(elements); superLock.lock(); try { TIdentityHashSet<CleaningNode> newElements = DependencyTracker.getAllDependentNodes(nodes, elements); if (!newElements.containsAll(elements)) { // we have to unlock all locks and lock them again among with new ones as advanced locking // algorithm // locks guarantees the absence of deadlocks only if all locks are locked at once. superLock.unlock(); elements.addAll(newElements); continue; } return new RecursiveLock(elements, superLock); } catch (Error e) { // we have to unlock it on exception superLock.unlock(); throw e; } catch (RuntimeException e) { // we have to unlock it on exception superLock.unlock(); throw e; } } }
public static void lockAndClear(Collection<? extends CleaningNode> elements) { Iterable<DependencyNode> nodes = nodeMapping(elements); TIdentityHashSet<CleaningNode> elementsAndDependent = DependencyTracker.getAllDependentNodes(nodes, elements); while (true) { SuperLock superLock = getSuperLock(elementsAndDependent); superLock.lock(); try { TIdentityHashSet<CleaningNode> newElements = DependencyTracker.getAllDependentNodes(nodes, elements); if (newElements.equals(elementsAndDependent)) { for (CleaningNode element : elementsAndDependent) { element.clear(); } return; } // the set of dependent caches has been altered, lock everything again elementsAndDependent = newElements; } finally { superLock.unlock(); } } }
public static void clear(@Nonnull CleanableInstanceList list) { List<WeakList<?>> lists = new ArrayList<WeakList<?>>(); List<CleaningNode> elements = new ArrayList<CleaningNode>(); Iterable<DependencyNode> nodes = nodeMapping(elements); outer: while (true) { int subtreeVersion = list.deepLock(); try { lists.clear(); list.getLists(lists); } finally { list.deepUnlock(); } int listsVersion = lockLists(lists); try { elements.clear(); list.getCaches(elements); } finally { unlockLists(lists); } TIdentityHashSet<CleaningNode> elementsAndDependent = DependencyTracker.getAllDependentNodes(nodes, elements); // dependency modification check loop while (true) { SuperLock superLock = getSuperLock(elementsAndDependent); superLock.lock(); try { TIdentityHashSet<CleaningNode> newElements = DependencyTracker.getAllDependentNodes(nodes, elements); if (!newElements.equals(elementsAndDependent)) { // the set of dependent caches has been altered, lock everything again elementsAndDependent = newElements; continue; } int newSubtreeVersion = list.deepLock(); try { if (newSubtreeVersion != subtreeVersion) { continue outer; } int newListsVersion = lockLists(lists); try { if (newListsVersion != listsVersion) { continue outer; } clear(elementsAndDependent); return; } finally { unlockLists(lists); } } finally { list.deepUnlock(); } } finally { superLock.unlock(); } } } }