]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeCache.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / NodeCache.java
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 (file)
index 0000000..04af108
--- /dev/null
@@ -0,0 +1,126 @@
+package org.simantics.db.layer0.variable;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.TreeMap;\r
+\r
+import gnu.trove.map.hash.TObjectLongHashMap;\r
+\r
+/**\r
+ * @author Antti Villberg\r
+ *\r
+ * @param <Node>\r
+ * @param <Value>\r
+ * \r
+ * @since 1.23\r
+ */\r
+public class NodeCache<Node,Value> {\r
+\r
+       // Expiration time for items in this cache\r
+       private long defaultExpirationTimeInNs;\r
+\r
+       // Here we hold all nodes with finite expiration times\r
+       private TreeMap<Long,Node> expirationTimes = new TreeMap<Long,Node>();\r
+       // Finite expiration times for nodes\r
+       private TObjectLongHashMap<Node> exp = new TObjectLongHashMap<Node>(10, 0.5f, -1L);\r
+       \r
+       // All node values\r
+       private Map<Node,Value> map = new HashMap<Node,Value>();\r
+\r
+       private boolean disposed;\r
+\r
+       public NodeCache() {\r
+               this(1_000_000_000L);\r
+       }\r
+\r
+       public NodeCache(long defaultExpirationTimeInNs) {\r
+               this.defaultExpirationTimeInNs = defaultExpirationTimeInNs;\r
+       }\r
+\r
+       public synchronized Value get(Node node) {\r
+               return map.get(node); \r
+       }\r
+       \r
+       public synchronized void clearExpired() {\r
+               \r
+               long now = System.nanoTime();\r
+               while(!expirationTimes.isEmpty()) {\r
+                       Long first = expirationTimes.firstKey();\r
+                       if(first < now) {\r
+                               Node node = expirationTimes.remove(first);\r
+                               exp.remove(node);\r
+                               map.remove(node);\r
+                       } else {\r
+                               return;\r
+                       }\r
+               }\r
+               \r
+       }\r
+\r
+       private long scheduleExpiration(Node node, long expiration) {\r
+               while(expirationTimes.containsKey(expiration)) expiration++;\r
+               expirationTimes.put(expiration, node);\r
+               exp.put(node, expiration);\r
+               return expiration;\r
+       }\r
+       \r
+       private void refreshExpiration(Node node, long newExpiration, boolean existing) {\r
+               \r
+               long current = exp.get(node);\r
+               if(current == -1) {\r
+                       if(existing) {\r
+                               // We have infinite expiration => do nothing\r
+                       } else {\r
+                               // This is a new value\r
+                               if(newExpiration == 0) {\r
+                                       // We require infinite expiration => do nothing\r
+                               } else {\r
+                                       scheduleExpiration(node, newExpiration);\r
+                               }\r
+                       }\r
+                       return;\r
+               }\r
+               \r
+               // This node is already under expiration tracking\r
+               if(newExpiration == 0) {\r
+                       // We now want infinite expiration => remove expiration time info\r
+                       expirationTimes.remove(current);\r
+                       exp.remove(node);\r
+               } else {\r
+                       if(newExpiration > current) {\r
+                               // Update expiration time\r
+                               expirationTimes.remove(current);\r
+                               scheduleExpiration(node, newExpiration);\r
+                       }\r
+               }\r
+               \r
+       }\r
+\r
+       public synchronized void put(Node node, Value value) {\r
+               if (disposed)\r
+                       return;\r
+               Value existing = map.put(node, value);\r
+               refreshExpiration(node, 0, existing != null);\r
+       }\r
+\r
+       public synchronized void put(Node node, Value value, long expiration) {\r
+               if (disposed)\r
+                       return;\r
+               Value existing = map.put(node, value);\r
+               refreshExpiration(node, System.nanoTime() + expiration, existing != null);\r
+       }\r
+\r
+       public synchronized void removeListening(Node node) {\r
+               if (disposed)\r
+                       return;\r
+               scheduleExpiration(node, System.nanoTime() + defaultExpirationTimeInNs);\r
+       }\r
+\r
+       public synchronized void dispose() {\r
+               disposed = true;\r
+               expirationTimes.clear();\r
+               exp.clear();\r
+               map.clear();\r
+       }\r
+       \r
+}\r