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;
18 import org.slf4j.LoggerFactory;
20 import gnu.trove.map.hash.TIntIntHashMap;
23 public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
25 private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ClusterLRU.class);
27 final private BijectionMap<ClusterUID, Integer> clusterMapping = new BijectionMap<ClusterUID, Integer>();
29 public ClusterLRU(ClusterManager manager, String identifier, Path writeDir) {
30 super(manager, identifier, writeDir);
32 clusterMapping.map(ClusterUID.make(0,2), clusterMapping.size() + 1);
35 public ClusterInfo getOrCreate(ClusterUID uid, boolean makeIfNull) throws IllegalAcornStateException, AcornAccessVerificationException {
41 ClusterInfo info = get(uid);
45 if(!makeIfNull) throw new IllegalAcornStateException("Asked for an existing cluster " + uid + " that was not found.");
47 Integer clusterKey = clusterMapping.getRight(uid);
48 if (clusterKey == null) {
49 clusterKey = clusterMapping.size() + 1;
50 clusterMapping.map(uid, clusterKey);
53 info = new ClusterInfo(manager, this, ClusterImpl.make(manager.support,
54 uid, clusterKey, manager.support));
59 } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
61 } catch (Throwable t) {
62 throw new IllegalAcornStateException(t);
72 * This method waits - we have no locks here
74 public void ensureUpdates(ClusterUID uid) throws ClusterDoesNotExistException, AcornAccessVerificationException, IllegalAcornStateException {
76 ClusterInfo info = getWithoutMutex(uid);
78 throw new ClusterDoesNotExistException("Asked a cluster which does not exist: " + uid);
79 info.waitForUpdates();
82 public ClusterInfo get(ClusterUID uid, boolean makeIfNull, boolean ensureUpdates) throws AcornAccessVerificationException, IllegalAcornStateException {
87 } catch (ClusterDoesNotExistException e) {
89 Logger.defaultLogError("For debug purposes, creating cluster which does not exist", e);
91 throw new IllegalAcornStateException(e);
95 return getOrCreate(uid, makeIfNull);
98 public ClusterInfo get(ClusterUID uid, boolean makeIfNull) throws AcornAccessVerificationException, IllegalAcornStateException {
99 return get(uid, makeIfNull, true);
102 public int getResourceKey(ClusterUID uid, int index) throws AcornAccessVerificationException {
104 if(VERIFY) verifyAccess();
106 Integer i = clusterMapping.getRight(uid);
108 i = clusterMapping.size() + 1;
109 clusterMapping.map(uid, i);
111 return (i << 12) + index;
115 public int getResourceKeyWithoutMutex(ClusterUID uid, int index) throws IllegalAcornStateException {
119 return getResourceKey(uid, index);
120 } catch (Throwable t) {
121 throw new IllegalAcornStateException(t);
127 public int createClusterKeyByClusterUID(ClusterUID uid) throws AcornAccessVerificationException {
129 if(VERIFY) verifyAccess();
131 Integer i = clusterMapping.getRight(uid);
133 i = clusterMapping.size() + 1;
134 clusterMapping.map(uid, i);
140 public ClusterBase getClusterByClusterUIDOrMake(ClusterUID uid) throws AcornAccessVerificationException, IllegalAcornStateException {
142 if(VERIFY) verifyAccess();
144 int key = createClusterKeyByClusterUID(uid);
145 return getClusterByClusterKey(key);
149 public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) throws AcornAccessVerificationException {
151 if(VERIFY) verifyAccess();
153 return createClusterKeyByClusterUID(clusterUID);
157 public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) throws IllegalAcornStateException, AcornAccessVerificationException {
160 return getClusterKeyByClusterUIDOrMake(clusterUID);
161 } catch (AcornAccessVerificationException e) {
163 } catch (Throwable t) {
164 throw new IllegalAcornStateException(t);
170 public ClusterBase getClusterByClusterKey(int clusterKey) throws AcornAccessVerificationException, IllegalAcornStateException {
172 if(VERIFY) verifyAccess();
174 ClusterUID uid = clusterMapping.getLeft(clusterKey);
175 ClusterInfo info = get(uid, true);
178 return info.getCluster();
179 } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
181 } catch (Throwable t) {
182 throw new IllegalAcornStateException(t);
188 public ClusterUID getClusterUIDByResourceKey(int resourceKey) throws AcornAccessVerificationException {
190 if(VERIFY) verifyAccess();
192 int clusterKey = resourceKey >> 12;
193 return clusterMapping.getLeft(clusterKey);
197 public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws IllegalAcornStateException, AcornAccessVerificationException {
200 return getClusterUIDByResourceKey(resourceKey);
206 @SuppressWarnings("unchecked")
207 public <T extends ClusterI> T getClusterByClusterUIDOrMakeProxy(ClusterUID uid) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
208 return (T) getClusterByClusterUIDOrMake(uid);
211 @SuppressWarnings("unchecked")
212 public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
214 if(VERIFY) verifyAccess();
216 return (T) getClusterByClusterKey(resourceKey >> 12);
220 public int getClusterKeyByUID(long id1, long id2) throws DatabaseException, AcornAccessVerificationException {
222 if(VERIFY) verifyAccess();
224 return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
228 public int getClusterKeyByUIDWithoutMutex(long id1, long id2) throws DatabaseException, IllegalAcornStateException {
231 return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
232 } catch (Throwable t) {
233 throw new IllegalAcornStateException(t);
240 public static void main(String[] args) throws Exception {
242 long start = System.nanoTime();
244 final TIntIntHashMap map = new TIntIntHashMap(0, 0.9f);
246 AtomicInteger counter = new AtomicInteger(0);
247 AtomicBoolean written = new AtomicBoolean(false);
249 //final Semaphore ws = new Semaphore(1);
251 Thread write = new Thread() {
256 for(int i=0;i<100000000;i++) {
262 //if((i & 0xfffff) == 0) System.err.println("Write " + i);
263 counter.incrementAndGet();
266 } catch (Throwable e) {
274 Thread read = new Thread() {
279 while(!written.get()) {
280 double r = Math.random();
281 double max = counter.get();
282 int key = (int)(max*r);
283 int value = map.get(key);
285 //System.err.println("Read failed " + key + " vs. " + value);
288 value = map.get(key);
290 LOGGER.warn("Read failed for real " + key + " vs. " + value);
295 //if((key & 0xfffff) == 0) System.err.println("Read " + key);
297 } catch (Throwable e) {
308 if (LOGGER.isDebugEnabled()) {
309 long duration = System.nanoTime() - start;
310 LOGGER.debug("took " + 1e-9*duration + "s.");