1 package org.simantics.acorn.lru;
3 import java.nio.file.Path;
4 import java.util.concurrent.atomic.AtomicBoolean;
5 import java.util.concurrent.atomic.AtomicInteger;
7 import org.simantics.acorn.ClusterManager;
8 import org.simantics.acorn.cluster.ClusterImpl;
9 import org.simantics.acorn.exception.AcornAccessVerificationException;
10 import org.simantics.acorn.exception.IllegalAcornStateException;
11 import org.simantics.acorn.internal.BijectionMap;
12 import org.simantics.db.common.utils.Logger;
13 import org.simantics.db.exception.ClusterDoesNotExistException;
14 import org.simantics.db.exception.DatabaseException;
15 import org.simantics.db.impl.ClusterBase;
16 import org.simantics.db.impl.ClusterI;
17 import org.simantics.db.service.ClusterUID;
19 import gnu.trove.TIntIntHashMap;
21 public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
23 final private BijectionMap<ClusterUID, Integer> clusterMapping = new BijectionMap<ClusterUID, Integer>();
25 public ClusterLRU(ClusterManager manager, String identifier, Path writeDir) {
26 super(manager, identifier, writeDir);
28 clusterMapping.map(ClusterUID.make(0,2), clusterMapping.size() + 1);
31 public ClusterInfo getOrCreate(ClusterUID uid, boolean makeIfNull) throws IllegalAcornStateException, AcornAccessVerificationException {
37 ClusterInfo info = get(uid);
41 if(!makeIfNull) throw new IllegalAcornStateException("Asked for an existing cluster " + uid + " that was not found.");
43 Integer clusterKey = clusterMapping.getRight(uid);
44 if (clusterKey == null) {
45 clusterKey = clusterMapping.size() + 1;
46 clusterMapping.map(uid, clusterKey);
49 info = new ClusterInfo(manager, this, ClusterImpl.make(manager.support,
50 uid, clusterKey, manager.support));
55 } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
57 } catch (Throwable t) {
58 throw new IllegalAcornStateException(t);
68 * This method waits - we have no locks here
70 public void ensureUpdates(ClusterUID uid) throws ClusterDoesNotExistException, AcornAccessVerificationException, IllegalAcornStateException {
72 ClusterInfo info = getWithoutMutex(uid);
74 throw new ClusterDoesNotExistException("Asked a cluster which does not exist: " + uid);
75 info.waitForUpdates();
78 public ClusterInfo get(ClusterUID uid, boolean makeIfNull, boolean ensureUpdates) throws AcornAccessVerificationException, IllegalAcornStateException {
83 } catch (ClusterDoesNotExistException e) {
85 Logger.defaultLogError("For debug purposes, creating cluster which does not exist", e);
87 throw new IllegalAcornStateException(e);
91 return getOrCreate(uid, makeIfNull);
94 public ClusterInfo get(ClusterUID uid, boolean makeIfNull) throws AcornAccessVerificationException, IllegalAcornStateException {
95 return get(uid, makeIfNull, true);
98 public int getResourceKey(ClusterUID uid, int index) throws AcornAccessVerificationException {
100 if(VERIFY) verifyAccess();
102 Integer i = clusterMapping.getRight(uid);
104 i = clusterMapping.size() + 1;
105 clusterMapping.map(uid, i);
107 return (i << 12) + index;
111 public int getResourceKeyWithoutMutex(ClusterUID uid, int index) throws IllegalAcornStateException {
115 return getResourceKey(uid, index);
116 } catch (Throwable t) {
117 throw new IllegalAcornStateException(t);
123 public int createClusterKeyByClusterUID(ClusterUID uid) throws AcornAccessVerificationException {
125 if(VERIFY) verifyAccess();
127 Integer i = clusterMapping.getRight(uid);
129 i = clusterMapping.size() + 1;
130 clusterMapping.map(uid, i);
136 public ClusterBase getClusterByClusterUIDOrMake(ClusterUID uid) throws AcornAccessVerificationException, IllegalAcornStateException {
138 if(VERIFY) verifyAccess();
140 int key = createClusterKeyByClusterUID(uid);
141 return getClusterByClusterKey(key);
145 public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) throws AcornAccessVerificationException {
147 if(VERIFY) verifyAccess();
149 return createClusterKeyByClusterUID(clusterUID);
153 public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) throws IllegalAcornStateException, AcornAccessVerificationException {
156 return getClusterKeyByClusterUIDOrMake(clusterUID);
157 } catch (AcornAccessVerificationException e) {
159 } catch (Throwable t) {
160 throw new IllegalAcornStateException(t);
166 public ClusterBase getClusterByClusterKey(int clusterKey) throws AcornAccessVerificationException, IllegalAcornStateException {
168 if(VERIFY) verifyAccess();
170 ClusterUID uid = clusterMapping.getLeft(clusterKey);
171 ClusterInfo info = get(uid, true);
174 return info.getCluster();
175 } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
177 } catch (Throwable t) {
178 throw new IllegalAcornStateException(t);
184 public ClusterUID getClusterUIDByResourceKey(int resourceKey) throws AcornAccessVerificationException {
186 if(VERIFY) verifyAccess();
188 int clusterKey = resourceKey >> 12;
189 return clusterMapping.getLeft(clusterKey);
193 public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws IllegalAcornStateException, AcornAccessVerificationException {
196 return getClusterUIDByResourceKey(resourceKey);
202 @SuppressWarnings("unchecked")
203 public <T extends ClusterI> T getClusterByClusterUIDOrMakeProxy(ClusterUID uid) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
204 return (T) getClusterByClusterUIDOrMake(uid);
207 @SuppressWarnings("unchecked")
208 public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
210 if(VERIFY) verifyAccess();
212 return (T) getClusterByClusterKey(resourceKey >> 12);
216 public int getClusterKeyByUID(long id1, long id2) throws DatabaseException, AcornAccessVerificationException {
218 if(VERIFY) verifyAccess();
220 return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
224 public int getClusterKeyByUIDWithoutMutex(long id1, long id2) throws DatabaseException, IllegalAcornStateException {
227 return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
228 } catch (Throwable t) {
229 throw new IllegalAcornStateException(t);
236 public static void main(String[] args) throws Exception {
238 long start = System.nanoTime();
240 final TIntIntHashMap map = new TIntIntHashMap(0, 0.9f);
242 AtomicInteger counter = new AtomicInteger(0);
243 AtomicBoolean written = new AtomicBoolean(false);
245 //final Semaphore ws = new Semaphore(1);
247 Thread write = new Thread() {
252 for(int i=0;i<100000000;i++) {
258 //if((i & 0xfffff) == 0) System.err.println("Write " + i);
259 counter.incrementAndGet();
262 } catch (Throwable e) {
270 Thread read = new Thread() {
275 while(!written.get()) {
276 double r = Math.random();
277 double max = counter.get();
278 int key = (int)(max*r);
279 int value = map.get(key);
281 //System.err.println("Read failed " + key + " vs. " + value);
284 value = map.get(key);
286 System.err.println("Read failed for real " + key + " vs. " + value);
291 //if((key & 0xfffff) == 0) System.err.println("Read " + key);
293 } catch (Throwable e) {
304 long duration = System.nanoTime() - start;
305 System.err.println("took " + 1e-9*duration + "s.");