]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeCache.java
Merge commit 'ad8333027322fda6b9a8a524c7a7e15a54c52f38'
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / NodeCache.java
1 package org.simantics.db.layer0.variable;\r
2 \r
3 import java.util.HashMap;\r
4 import java.util.Map;\r
5 import java.util.TreeMap;\r
6 \r
7 import gnu.trove.map.hash.TObjectLongHashMap;\r
8 \r
9 /**\r
10  * @author Antti Villberg\r
11  *\r
12  * @param <Node>\r
13  * @param <Value>\r
14  * \r
15  * @since 1.23\r
16  */\r
17 public class NodeCache<Node,Value> {\r
18 \r
19         // Expiration time for items in this cache\r
20         private long defaultExpirationTimeInNs;\r
21 \r
22         // Here we hold all nodes with finite expiration times\r
23         private TreeMap<Long,Node> expirationTimes = new TreeMap<Long,Node>();\r
24         // Finite expiration times for nodes\r
25         private TObjectLongHashMap<Node> exp = new TObjectLongHashMap<Node>(10, 0.5f, -1L);\r
26         \r
27         // All node values\r
28         private Map<Node,Value> map = new HashMap<Node,Value>();\r
29 \r
30         private boolean disposed;\r
31 \r
32         public NodeCache() {\r
33                 this(1_000_000_000L);\r
34         }\r
35 \r
36         public NodeCache(long defaultExpirationTimeInNs) {\r
37                 this.defaultExpirationTimeInNs = defaultExpirationTimeInNs;\r
38         }\r
39 \r
40         public synchronized Value get(Node node) {\r
41                 return map.get(node); \r
42         }\r
43         \r
44         public synchronized void clearExpired() {\r
45                 \r
46                 long now = System.nanoTime();\r
47                 while(!expirationTimes.isEmpty()) {\r
48                         Long first = expirationTimes.firstKey();\r
49                         if(first < now) {\r
50                                 Node node = expirationTimes.remove(first);\r
51                                 exp.remove(node);\r
52                                 map.remove(node);\r
53                         } else {\r
54                                 return;\r
55                         }\r
56                 }\r
57                 \r
58         }\r
59 \r
60         private long scheduleExpiration(Node node, long expiration) {\r
61                 while(expirationTimes.containsKey(expiration)) expiration++;\r
62                 expirationTimes.put(expiration, node);\r
63                 exp.put(node, expiration);\r
64                 return expiration;\r
65         }\r
66         \r
67         private void refreshExpiration(Node node, long newExpiration, boolean existing) {\r
68                 \r
69                 long current = exp.get(node);\r
70                 if(current == -1) {\r
71                         if(existing) {\r
72                                 // We have infinite expiration => do nothing\r
73                         } else {\r
74                                 // This is a new value\r
75                                 if(newExpiration == 0) {\r
76                                         // We require infinite expiration => do nothing\r
77                                 } else {\r
78                                         scheduleExpiration(node, newExpiration);\r
79                                 }\r
80                         }\r
81                         return;\r
82                 }\r
83                 \r
84                 // This node is already under expiration tracking\r
85                 if(newExpiration == 0) {\r
86                         // We now want infinite expiration => remove expiration time info\r
87                         expirationTimes.remove(current);\r
88                         exp.remove(node);\r
89                 } else {\r
90                         if(newExpiration > current) {\r
91                                 // Update expiration time\r
92                                 expirationTimes.remove(current);\r
93                                 scheduleExpiration(node, newExpiration);\r
94                         }\r
95                 }\r
96                 \r
97         }\r
98 \r
99         public synchronized void put(Node node, Value value) {\r
100                 if (disposed)\r
101                         return;\r
102                 Value existing = map.put(node, value);\r
103                 refreshExpiration(node, 0, existing != null);\r
104         }\r
105 \r
106         public synchronized void put(Node node, Value value, long expiration) {\r
107                 if (disposed)\r
108                         return;\r
109                 Value existing = map.put(node, value);\r
110                 refreshExpiration(node, System.nanoTime() + expiration, existing != null);\r
111         }\r
112 \r
113         public synchronized void removeListening(Node node) {\r
114                 if (disposed)\r
115                         return;\r
116                 scheduleExpiration(node, System.nanoTime() + defaultExpirationTimeInNs);\r
117         }\r
118 \r
119         public synchronized void dispose() {\r
120                 disposed = true;\r
121                 expirationTimes.clear();\r
122                 exp.clear();\r
123                 map.clear();\r
124         }\r
125         \r
126 }\r