]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterLRU.java
Sharing org.simantics.acorn for everyone to use
[simantics/platform.git] / bundles / org.simantics.acorn / src / org / simantics / acorn / lru / ClusterLRU.java
diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterLRU.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterLRU.java
new file mode 100644 (file)
index 0000000..1f0db54
--- /dev/null
@@ -0,0 +1,315 @@
+package org.simantics.acorn.lru;
+
+import java.nio.file.Path;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.simantics.acorn.ClusterManager;
+import org.simantics.acorn.cluster.ClusterImpl;
+import org.simantics.acorn.internal.BijectionMap;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.exception.ClusterDoesNotExistException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.impl.ClusterBase;
+import org.simantics.db.impl.ClusterI;
+import org.simantics.db.service.ClusterUID;
+
+import gnu.trove.TIntIntHashMap;
+
+public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
+
+       final private BijectionMap<ClusterUID, Integer> clusterMapping = new BijectionMap<ClusterUID, Integer>();
+       final private ClusterManager manager;
+       
+       public ClusterLRU(ClusterManager manager, String identifier, Path writeDir) {
+               
+               super(identifier, writeDir);
+               this.manager = manager;
+               
+               clusterMapping.map(ClusterUID.make(0,2), clusterMapping.size() + 1);
+
+       }
+
+       public ClusterInfo getOrCreate(ClusterUID uid, boolean makeIfNull) {
+               
+               try {
+                       
+                       acquireMutex();
+                       
+                       ClusterInfo info = get(uid);
+
+                       if (info == null) {
+                               
+                               if(!makeIfNull) throw new IllegalStateException("Asked for an existing cluster " + uid + " that was not found.");
+
+                               Integer clusterKey = clusterMapping.getRight(uid);
+                               if (clusterKey == null) {
+                                       clusterKey = clusterMapping.size() + 1;
+                                       clusterMapping.map(uid, clusterKey);
+                               }
+
+                               info = new ClusterInfo(manager, this, ClusterImpl.make(manager.support,
+                                               uid, clusterKey, manager.support));
+
+                       }
+
+                       return info;
+                       
+               } catch (Throwable t) {
+                       throw new IllegalStateException(t);
+               } finally {
+                       
+                       releaseMutex();
+                       
+               }
+               
+       }
+
+       /*
+        * This method waits - we have no locks here
+        */
+       public void ensureUpdates(ClusterUID uid) throws DatabaseException {
+
+               ClusterInfo info = getWithoutMutex(uid);
+               if(info == null)
+                   throw new ClusterDoesNotExistException("Asked a cluster which does not exist: " + uid);
+               info.waitForUpdates();
+               
+       }
+
+       public ClusterInfo get(ClusterUID uid, boolean makeIfNull, boolean ensureUpdates) throws DatabaseException {
+
+               if (ensureUpdates) {
+                   try {
+                       ensureUpdates(uid);
+                   } catch (ClusterDoesNotExistException e) {
+                       if (makeIfNull) {
+                           Logger.defaultLogError("For debug purposes, creating cluster which does not exist", e);
+                       } else {
+                           throw e;
+                       }
+                   }
+               }
+               return getOrCreate(uid, makeIfNull);
+       }
+       
+       public ClusterInfo get(ClusterUID uid, boolean makeIfNull) throws DatabaseException {
+               return get(uid, makeIfNull, true);
+               
+       }
+
+       public int getResourceKey(ClusterUID uid, int index) {
+
+               if(VERIFY) verifyAccess();
+
+               Integer i = clusterMapping.getRight(uid);
+               if (i == null) {
+                       i = clusterMapping.size() + 1;
+                       clusterMapping.map(uid, i);
+               }
+               return (i << 12) + index;
+
+       }
+
+       public int getResourceKeyWithoutMutex(ClusterUID uid, int index) {
+               
+               acquireMutex();
+               try {
+                       return getResourceKey(uid, index);
+               } catch (Throwable t) {
+                       throw new IllegalStateException(t);
+               } finally {
+                       releaseMutex();
+               }
+               
+       }
+
+       public int createClusterKeyByClusterUID(ClusterUID uid) {
+               
+               if(VERIFY) verifyAccess();
+               
+               Integer i = clusterMapping.getRight(uid);
+               if (i == null) {
+                       i = clusterMapping.size() + 1;
+                       clusterMapping.map(uid, i);
+               }
+               return i;
+               
+       }
+
+       public ClusterBase getClusterByClusterUIDOrMake(ClusterUID uid) throws DatabaseException {
+               
+               if(VERIFY) verifyAccess();
+               
+               int key = createClusterKeyByClusterUID(uid);
+               return getClusterByClusterKey(key);
+               
+       }
+
+       public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) {
+
+               if(VERIFY) verifyAccess();
+
+               return createClusterKeyByClusterUID(clusterUID);
+                       
+       }
+       
+       public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) {
+               acquireMutex();
+               try {
+                       return getClusterKeyByClusterUIDOrMake(clusterUID);
+               } catch (Throwable t) {
+                       throw new IllegalStateException(t);
+               } finally {
+                       releaseMutex();
+               }
+       }
+
+       public ClusterBase getClusterByClusterKey(int clusterKey) throws DatabaseException {
+               
+               if(VERIFY) verifyAccess();
+               
+               ClusterUID uid = clusterMapping.getLeft(clusterKey);
+               ClusterInfo info = get(uid, true);
+               info.acquireMutex();
+               try {
+                       return info.getCluster();
+               } catch (Throwable t) {
+                       throw new IllegalStateException(t);
+               } finally {
+                       info.releaseMutex();
+               }
+               
+       }
+
+       public ClusterUID getClusterUIDByResourceKey(int resourceKey)
+                       throws DatabaseException {
+               
+               if(VERIFY) verifyAccess();
+               
+               int clusterKey = resourceKey >> 12;
+               return clusterMapping.getLeft(clusterKey);
+               
+       }
+       
+       public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws DatabaseException {
+               acquireMutex();
+               try {
+                       return getClusterUIDByResourceKey(resourceKey);
+               } catch (Throwable t) {
+                       throw new IllegalStateException(t);
+               } finally {
+                       releaseMutex();
+               }
+       }
+
+       @SuppressWarnings("unchecked")
+       public <T extends ClusterI> T getClusterByClusterUIDOrMakeProxy(ClusterUID uid) throws DatabaseException {
+               return (T) getClusterByClusterUIDOrMake(uid);
+       }
+
+       @SuppressWarnings("unchecked")
+       public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException {
+               
+               if(VERIFY) verifyAccess();
+
+               return (T) getClusterByClusterKey(resourceKey >> 12);
+               
+       }
+
+       public int getClusterKeyByUID(long id1, long id2) throws DatabaseException {
+               
+               if(VERIFY) verifyAccess();
+
+               return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
+               
+       }
+       
+       public int getClusterKeyByUIDWithoutMutex(long id1, long id2) throws DatabaseException {
+
+               acquireMutex();
+               try {
+                       return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
+               } catch (Throwable t) {
+                       throw new IllegalStateException(t);
+               } finally {
+                       releaseMutex();
+               }
+
+       }
+
+       
+       public static void main(String[] args) throws Exception {
+               
+               long start = System.nanoTime();
+               
+               final TIntIntHashMap map = new TIntIntHashMap(0, 0.9f);
+
+               AtomicInteger counter = new AtomicInteger(0);
+               AtomicBoolean written = new AtomicBoolean(false);
+               
+               //final Semaphore ws = new Semaphore(1);
+               
+               Thread write = new Thread() {
+                       
+                       @Override
+                       public void run() {
+                               try {
+                                       for(int i=0;i<100000000;i++) {
+                                               synchronized(map) {
+//                                             ws.acquire();
+                                               map.put(i, i);
+//                                             ws.release();
+                                               }
+                                               //if((i & 0xfffff) == 0) System.err.println("Write " + i);
+                                               counter.incrementAndGet();
+                                       }
+                                       written.set(true);
+                               } catch (Throwable e) {
+                                       e.printStackTrace();
+                               }
+                       }
+                       
+               };
+               write.start();
+               
+               Thread read = new Thread() {
+                       
+                       @Override
+                       public void run() {
+                               try {
+                                       while(!written.get()) {
+                                               double r = Math.random();
+                                               double max = counter.get();
+                                               int key = (int)(max*r);
+                                               int value = map.get(key);
+                                               if(key != value) {
+                                                       //System.err.println("Read failed " + key + " vs. " + value);
+                                                       //ws.acquire();
+                                                       synchronized(map) {
+                                                               value = map.get(key);
+                                                               if(key != value) {
+                                                                       System.err.println("Read failed for real " + key + " vs. " + value);
+                                                               }
+                                                               //ws.release();
+                                                       }
+                                               }
+                                               //if((key & 0xfffff) == 0) System.err.println("Read " + key);
+                                       }
+                               } catch (Throwable e) {
+                                       e.printStackTrace();
+                               }
+                       }
+                       
+               };
+               read.start();
+               
+               write.join();
+               read.join();
+               
+               long duration = System.nanoTime() - start;
+               System.err.println("took " + 1e-9*duration + "s.");
+               
+       }
+       
+}