X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.db.layer0%2Fsrc%2Forg%2Fsimantics%2Fdb%2Flayer0%2Fvariable%2FNodeCache.java;fp=bundles%2Forg.simantics.db.layer0%2Fsrc%2Forg%2Fsimantics%2Fdb%2Flayer0%2Fvariable%2FNodeCache.java;h=04af108401c2cfcff4e404cc5f29fbf93dc49814;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeCache.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeCache.java new file mode 100644 index 000000000..04af10840 --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeCache.java @@ -0,0 +1,126 @@ +package org.simantics.db.layer0.variable; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import gnu.trove.map.hash.TObjectLongHashMap; + +/** + * @author Antti Villberg + * + * @param + * @param + * + * @since 1.23 + */ +public class NodeCache { + + // Expiration time for items in this cache + private long defaultExpirationTimeInNs; + + // Here we hold all nodes with finite expiration times + private TreeMap expirationTimes = new TreeMap(); + // Finite expiration times for nodes + private TObjectLongHashMap exp = new TObjectLongHashMap(10, 0.5f, -1L); + + // All node values + private Map map = new HashMap(); + + private boolean disposed; + + public NodeCache() { + this(1_000_000_000L); + } + + public NodeCache(long defaultExpirationTimeInNs) { + this.defaultExpirationTimeInNs = defaultExpirationTimeInNs; + } + + public synchronized Value get(Node node) { + return map.get(node); + } + + public synchronized void clearExpired() { + + long now = System.nanoTime(); + while(!expirationTimes.isEmpty()) { + Long first = expirationTimes.firstKey(); + if(first < now) { + Node node = expirationTimes.remove(first); + exp.remove(node); + map.remove(node); + } else { + return; + } + } + + } + + private long scheduleExpiration(Node node, long expiration) { + while(expirationTimes.containsKey(expiration)) expiration++; + expirationTimes.put(expiration, node); + exp.put(node, expiration); + return expiration; + } + + private void refreshExpiration(Node node, long newExpiration, boolean existing) { + + long current = exp.get(node); + if(current == -1) { + if(existing) { + // We have infinite expiration => do nothing + } else { + // This is a new value + if(newExpiration == 0) { + // We require infinite expiration => do nothing + } else { + scheduleExpiration(node, newExpiration); + } + } + return; + } + + // This node is already under expiration tracking + if(newExpiration == 0) { + // We now want infinite expiration => remove expiration time info + expirationTimes.remove(current); + exp.remove(node); + } else { + if(newExpiration > current) { + // Update expiration time + expirationTimes.remove(current); + scheduleExpiration(node, newExpiration); + } + } + + } + + public synchronized void put(Node node, Value value) { + if (disposed) + return; + Value existing = map.put(node, value); + refreshExpiration(node, 0, existing != null); + } + + public synchronized void put(Node node, Value value, long expiration) { + if (disposed) + return; + Value existing = map.put(node, value); + refreshExpiration(node, System.nanoTime() + expiration, existing != null); + } + + public synchronized void removeListening(Node node) { + if (disposed) + return; + scheduleExpiration(node, System.nanoTime() + defaultExpirationTimeInNs); + } + + public synchronized void dispose() { + disposed = true; + expirationTimes.clear(); + exp.clear(); + map.clear(); + } + +}