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