1 package org.simantics.db.layer0.variable;
\r
3 import java.util.HashMap;
\r
4 import java.util.Map;
\r
5 import java.util.TreeMap;
\r
7 import gnu.trove.map.hash.TObjectLongHashMap;
\r
10 * @author Antti Villberg
\r
17 public class NodeCache<Node,Value> {
\r
19 // Expiration time for items in this cache
\r
20 private long defaultExpirationTimeInNs;
\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
28 private Map<Node,Value> map = new HashMap<Node,Value>();
\r
30 private boolean disposed;
\r
32 public NodeCache() {
\r
33 this(1_000_000_000L);
\r
36 public NodeCache(long defaultExpirationTimeInNs) {
\r
37 this.defaultExpirationTimeInNs = defaultExpirationTimeInNs;
\r
40 public synchronized Value get(Node node) {
\r
41 return map.get(node);
\r
44 public synchronized void clearExpired() {
\r
46 long now = System.nanoTime();
\r
47 while(!expirationTimes.isEmpty()) {
\r
48 Long first = expirationTimes.firstKey();
\r
50 Node node = expirationTimes.remove(first);
\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
67 private void refreshExpiration(Node node, long newExpiration, boolean existing) {
\r
69 long current = exp.get(node);
\r
72 // We have infinite expiration => do nothing
\r
74 // This is a new value
\r
75 if(newExpiration == 0) {
\r
76 // We require infinite expiration => do nothing
\r
78 scheduleExpiration(node, newExpiration);
\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
90 if(newExpiration > current) {
\r
91 // Update expiration time
\r
92 expirationTimes.remove(current);
\r
93 scheduleExpiration(node, newExpiration);
\r
99 public synchronized void put(Node node, Value value) {
\r
102 Value existing = map.put(node, value);
\r
103 refreshExpiration(node, 0, existing != null);
\r
106 public synchronized void put(Node node, Value value, long expiration) {
\r
109 Value existing = map.put(node, value);
\r
110 refreshExpiration(node, System.nanoTime() + expiration, existing != null);
\r
113 public synchronized void removeListening(Node node) {
\r
116 scheduleExpiration(node, System.nanoTime() + defaultExpirationTimeInNs);
\r
119 public synchronized void dispose() {
\r
121 expirationTimes.clear();
\r