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.map.hash.TIntIntHashMap;
22 public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
24 final private BijectionMap<ClusterUID, Integer> clusterMapping = new BijectionMap<ClusterUID, Integer>();
26 public ClusterLRU(ClusterManager manager, String identifier, Path writeDir) {
27 super(manager, identifier, writeDir);
29 clusterMapping.map(ClusterUID.make(0,2), clusterMapping.size() + 1);
32 public ClusterInfo getOrCreate(ClusterUID uid, boolean makeIfNull) throws IllegalAcornStateException, AcornAccessVerificationException {
38 ClusterInfo info = get(uid);
42 if(!makeIfNull) throw new IllegalAcornStateException("Asked for an existing cluster " + uid + " that was not found.");
44 Integer clusterKey = clusterMapping.getRight(uid);
45 if (clusterKey == null) {
46 clusterKey = clusterMapping.size() + 1;
47 clusterMapping.map(uid, clusterKey);
50 info = new ClusterInfo(manager, this, ClusterImpl.make(manager.support,
51 uid, clusterKey, manager.support));
56 } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
58 } catch (Throwable t) {
59 throw new IllegalAcornStateException(t);
69 * This method waits - we have no locks here
71 public void ensureUpdates(ClusterUID uid) throws ClusterDoesNotExistException, AcornAccessVerificationException, IllegalAcornStateException {
73 ClusterInfo info = getWithoutMutex(uid);
75 throw new ClusterDoesNotExistException("Asked a cluster which does not exist: " + uid);
76 info.waitForUpdates();
79 public ClusterInfo get(ClusterUID uid, boolean makeIfNull, boolean ensureUpdates) throws AcornAccessVerificationException, IllegalAcornStateException {
84 } catch (ClusterDoesNotExistException e) {
86 Logger.defaultLogError("For debug purposes, creating cluster which does not exist", e);
88 throw new IllegalAcornStateException(e);
92 return getOrCreate(uid, makeIfNull);
95 public ClusterInfo get(ClusterUID uid, boolean makeIfNull) throws AcornAccessVerificationException, IllegalAcornStateException {
96 return get(uid, makeIfNull, true);
99 public int getResourceKey(ClusterUID uid, int index) throws AcornAccessVerificationException {
101 if(VERIFY) verifyAccess();
103 Integer i = clusterMapping.getRight(uid);
105 i = clusterMapping.size() + 1;
106 clusterMapping.map(uid, i);
108 return (i << 12) + index;
112 public int getResourceKeyWithoutMutex(ClusterUID uid, int index) throws IllegalAcornStateException {
116 return getResourceKey(uid, index);
117 } catch (Throwable t) {
118 throw new IllegalAcornStateException(t);
124 public int createClusterKeyByClusterUID(ClusterUID uid) throws AcornAccessVerificationException {
126 if(VERIFY) verifyAccess();
128 Integer i = clusterMapping.getRight(uid);
130 i = clusterMapping.size() + 1;
131 clusterMapping.map(uid, i);
137 public ClusterBase getClusterByClusterUIDOrMake(ClusterUID uid) throws AcornAccessVerificationException, IllegalAcornStateException {
139 if(VERIFY) verifyAccess();
141 int key = createClusterKeyByClusterUID(uid);
142 return getClusterByClusterKey(key);
146 public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) throws AcornAccessVerificationException {
148 if(VERIFY) verifyAccess();
150 return createClusterKeyByClusterUID(clusterUID);
154 public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) throws IllegalAcornStateException, AcornAccessVerificationException {
157 return getClusterKeyByClusterUIDOrMake(clusterUID);
158 } catch (AcornAccessVerificationException e) {
160 } catch (Throwable t) {
161 throw new IllegalAcornStateException(t);
167 public ClusterBase getClusterByClusterKey(int clusterKey) throws AcornAccessVerificationException, IllegalAcornStateException {
169 if(VERIFY) verifyAccess();
171 ClusterUID uid = clusterMapping.getLeft(clusterKey);
172 ClusterInfo info = get(uid, true);
175 return info.getCluster();
176 } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
178 } catch (Throwable t) {
179 throw new IllegalAcornStateException(t);
185 public ClusterUID getClusterUIDByResourceKey(int resourceKey) throws AcornAccessVerificationException {
187 if(VERIFY) verifyAccess();
189 int clusterKey = resourceKey >> 12;
190 return clusterMapping.getLeft(clusterKey);
194 public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws IllegalAcornStateException, AcornAccessVerificationException {
197 return getClusterUIDByResourceKey(resourceKey);
203 @SuppressWarnings("unchecked")
204 public <T extends ClusterI> T getClusterByClusterUIDOrMakeProxy(ClusterUID uid) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
205 return (T) getClusterByClusterUIDOrMake(uid);
208 @SuppressWarnings("unchecked")
209 public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
211 if(VERIFY) verifyAccess();
213 return (T) getClusterByClusterKey(resourceKey >> 12);
217 public int getClusterKeyByUID(long id1, long id2) throws DatabaseException, AcornAccessVerificationException {
219 if(VERIFY) verifyAccess();
221 return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
225 public int getClusterKeyByUIDWithoutMutex(long id1, long id2) throws DatabaseException, IllegalAcornStateException {
228 return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
229 } catch (Throwable t) {
230 throw new IllegalAcornStateException(t);
237 public static void main(String[] args) throws Exception {
239 long start = System.nanoTime();
241 final TIntIntHashMap map = new TIntIntHashMap(0, 0.9f);
243 AtomicInteger counter = new AtomicInteger(0);
244 AtomicBoolean written = new AtomicBoolean(false);
246 //final Semaphore ws = new Semaphore(1);
248 Thread write = new Thread() {
253 for(int i=0;i<100000000;i++) {
259 //if((i & 0xfffff) == 0) System.err.println("Write " + i);
260 counter.incrementAndGet();
263 } catch (Throwable e) {
271 Thread read = new Thread() {
276 while(!written.get()) {
277 double r = Math.random();
278 double max = counter.get();
279 int key = (int)(max*r);
280 int value = map.get(key);
282 //System.err.println("Read failed " + key + " vs. " + value);
285 value = map.get(key);
287 System.err.println("Read failed for real " + key + " vs. " + value);
292 //if((key & 0xfffff) == 0) System.err.println("Read " + key);
294 } catch (Throwable e) {
305 long duration = System.nanoTime() - start;
306 System.err.println("took " + 1e-9*duration + "s.");