/** * 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; } } }
@Override @SuppressWarnings({"unchecked"}) public long getOrCreate(float o) { if (DependencyTracker.isBypassCaches()) { return calculatable.calculate(owner, o); } else { preCheckDirty(); lock(o); try { Object v = load(o); ExceptionHelper.throwIfExceptionRecordNotExpired(v); if (v != UNDEFINED) { DependencyTracker.mark(getDependencyNode()); hit(); return (Long) v; } DependencyNode callerNode = DependencyTracker.track(getDependencyNode()); try { while (true) { try { return create(o); } catch (ResourceOccupied e) { if (callerNode != null) { throw e; } else { unlock(o); try { e.getResource().waitForEndOfModification(); } finally { lock(o); } v = load(o); ExceptionHelper.throwIfExceptionRecordNotExpired(v); if (v != UNDEFINED) { hit(); return (Long) v; } } } } } finally { DependencyTracker.exit(callerNode); } } finally { unlock(o); postCheckDirty(); } } }
@Override @SuppressWarnings({"unchecked"}) public F getOrCreate(E o) { if (DependencyTracker.isBypassCaches()) { return calculatable.calculate(owner, o); } else { lock(o); try { Object v = load(o); if (v != UNDEFINED) { DependencyTracker.mark(getDependencyNode()); hit(); return (F) v; } DependencyNode callerNode = DependencyTracker.track(getDependencyNode()); try { while (true) { try { return create(o); } catch (ResourceOccupied e) { if (callerNode != null) { throw e; } else { unlock(o); try { e.getResource().waitForEndOfModification(); } finally { lock(o); } v = load(o); if (v != UNDEFINED) { hit(); return (F) v; } } } } } finally { DependencyTracker.exit(callerNode); } } finally { unlock(o); } } }
@Override public char getOrCreate(boolean o) { if (DependencyTracker.isBypassCaches()) { return calculatable.calculate(owner, o); } else { lock(o); try { if (isCalculated(o)) { DependencyTracker.mark(getDependencyNode()); hit(); return load(o); } DependencyNode callerNode = DependencyTracker.track(getDependencyNode()); try { while (true) { try { return create(o); } catch (ResourceOccupied e) { if (callerNode != null) { throw e; } else { unlock(o); try { e.getResource().waitForEndOfModification(); } finally { lock(o); } if (isCalculated(o)) { hit(); return load(o); } } } } } finally { DependencyTracker.exit(callerNode); } } finally { unlock(o); } } }
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(); } } } }