]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterTable.java
Removed contact application support prints
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / ClusterTable.java
index 99aa9004f34d610f7a66636a47a9659d254566ee..6cab018a6f4beadde5859f94fc86de4b75638a92 100644 (file)
@@ -18,6 +18,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 
 import org.simantics.databoard.Bindings;
@@ -65,7 +66,7 @@ public final class ClusterTable implements IClusterTable {
     int maximumBytes = 128 * 1024 * 1024;
     int limit = (int)(0.8*(double)maximumBytes);
 
-    long timeCounter = 0;
+    private final AtomicLong timeCounter = new AtomicLong(1);
 
     final private SessionImplSocket sessionImpl;
     final private ArrayList<ClusterI> writeOnlyClusters = new ArrayList<ClusterI>();
@@ -93,6 +94,10 @@ public final class ClusterTable implements IClusterTable {
         public long getClusterId() {
             return clusterId;
         }
+        @Override
+        public String toString() {
+            return "CID " + clusterId;
+        }
     }
     private class Clusters {
         // This makes sure that non-null values from hashMap.get can be trusted (no unsynchronized rehashes occur)
@@ -130,7 +135,7 @@ public final class ClusterTable implements IClusterTable {
             int clusterKey = hashMap.size();
             ClusterSmall sentinel = new ClusterSmall(clusterUID, clusterKey, ClusterTable.this, sessionImpl.clusterTranslator);
             if (sentinel.clusterId != sentinel.clusterUID.second)
-                throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                throw new RuntimeDatabaseException("ClusterTable corrupted.");
             create(sentinel);
             return sentinel;
         }
@@ -139,25 +144,25 @@ public final class ClusterTable implements IClusterTable {
             create(proxy);
             if (null != old) {
                 if (old.clusterKey != proxy.clusterKey)
-                    throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                    throw new RuntimeDatabaseException("ClusterTable corrupted.");
                 if (old.clusterId != proxy.clusterId)
-                    throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                    throw new RuntimeDatabaseException("ClusterTable corrupted.");
                 if (!old.clusterUID.equals(proxy.clusterUID))
-                    throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                    throw new RuntimeDatabaseException("ClusterTable corrupted.");
             }
         }
         private ClusterSmall freeProxy(ClusterImpl proxy) {
             ClusterImpl clusterImpl = hashMap.get(proxy.clusterId);
             if (null == clusterImpl)
-                throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                throw new RuntimeDatabaseException("ClusterTable corrupted.");
 //            ClusterUID clusterUID = ClusterUID.make(0, proxy.clusterId);
 //            ClusterImpl clusterImpl2 = clusterU2I.get(clusterUID );
 //            if (clusterImpl != clusterImpl2)
-//                throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+//                throw new RuntimeDatabaseException("ClusterTable corrupted.");
             if (proxy.clusterId != clusterImpl.clusterId)
-                throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                throw new RuntimeDatabaseException("ClusterTable corrupted.");
             if (proxy.clusterKey != clusterImpl.clusterKey)
-                throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                throw new RuntimeDatabaseException("ClusterTable corrupted.");
             ClusterSmall sentinel = new ClusterSmall(makeClusterUID(proxy.clusterId) , proxy.clusterKey, ClusterTable.this, sessionImpl.clusterTranslator);
             return (ClusterSmall)create(sentinel);
         }
@@ -271,27 +276,48 @@ public final class ClusterTable implements IClusterTable {
             writeOnlyClusters.add(proxy);
             return clusters.create(proxy);
         } else {
+            //printMaps("makeCluster");
             ClusterImpl cluster = ClusterImpl.make(clusterUID, clusterKey, sessionImpl.clusterTranslator);
             clusters.create(cluster);
             if (!cluster.isLoaded())
                 Logger.defaultLogError(new Exception("Bug in ClusterTable.makeCluster(long, boolean), cluster not loaded"));
             importanceMap.put(cluster.getImportance(), new ImportanceEntry(cluster));
+            if (VALIDATE_SIZE)
+                validateSize("makeCluster");
             if(collectorPolicy != null) collectorPolicy.added(cluster);
             return cluster;
         }
     }
 
-    synchronized void replaceCluster(ClusterI cluster) {
+    synchronized void replaceCluster(ClusterI cluster_) {
+        ClusterImpl cluster = (ClusterImpl) cluster_;
         checkCollect();
         int clusterKey = cluster.getClusterKey();
-        ClusterI existing = clusterArray[clusterKey];
+        ClusterImpl existing = (ClusterImpl) clusterArray[clusterKey];
         if (existing.hasVirtual())
             cluster.markVirtual();
 
+        if (existing.cc != null) {
+            if (existing.isLoaded()) {
+                // This shall be promoted to actual exception in the future -
+                // for now, minimal changes
+                new Exception("Trying to replace cluster with pending changes " + existing.getClusterUID())
+                        .printStackTrace();
+            } else {
+                // Adopt changes to loaded cluster
+                cluster.cc = existing.cc;
+                cluster.cc.adopt(cluster);
+                cluster.foreignLookup = existing.foreignLookup;
+                cluster.change = existing.change;
+            }
+        }
+        
         importanceMap.remove(existing.getImportance());
         if (collectorPolicy != null)
             collectorPolicy.removed((ClusterImpl)existing);
 
+        //System.out.println("ClusterTable.replace(" + existing + " (I=" + existing.getImportance() + ") => " + cluster + " (I=" + cluster.getImportance() + ")");
+
         clusters.replace((ClusterImpl)cluster);
         if (!cluster.isLoaded())
             Logger.defaultLogError(new Exception("Bug in ClusterTable.replaceCluster(ClusterI), cluster not loaded"));
@@ -306,7 +332,8 @@ public final class ClusterTable implements IClusterTable {
             // This will update sizeInBytes through adjustCachedSize
             cluster.getCachedSize();
         }
-        validateSize();
+        if (VALIDATE_SIZE)
+            validateSize("replaceCluster");
     }
 
     synchronized void release(CollectorCluster cluster) {
@@ -322,6 +349,7 @@ public final class ClusterTable implements IClusterTable {
             return;
         if(!clusterImpl.isLoaded() || clusterImpl.isEmpty())
             return;
+        //printMaps("release");
         clusters.freeProxy(clusterImpl);
         importanceMap.remove(clusterImpl.getImportance());
         if (collectorPolicy != null)
@@ -331,6 +359,8 @@ public final class ClusterTable implements IClusterTable {
         if (!dirtySizeInBytes) {
             adjustCachedSize(-clusterImpl.getCachedSize(), clusterImpl);
         }
+        if (VALIDATE_SIZE)
+            validateSize("release");
     }
 
     synchronized void compact(long id) {
@@ -565,7 +595,7 @@ public final class ClusterTable implements IClusterTable {
     void removeWriteOnlyClusters() {
         for (ClusterI proxy : writeOnlyClusters) {
             if (!(proxy instanceof ClusterImpl))
-                throw new RuntimeDatabaseException("ClusterTable corrupted. Contact application support.");
+                throw new RuntimeDatabaseException("ClusterTable corrupted.");
             clusters.freeProxy((ClusterImpl)proxy);
         }
         writeOnlyClusters.clear();
@@ -574,7 +604,6 @@ public final class ClusterTable implements IClusterTable {
             public boolean execute(int clusterKey) {
                 ClusterImpl proxy = clusterArray[clusterKey];
                 ClusterUID clusterUID = proxy.getClusterUID();
-                System.err.println("writeOnlyInvalidate " + clusterUID);
                 clusters.freeProxy(proxy);
                 return true;
             }
@@ -687,6 +716,7 @@ public final class ClusterTable implements IClusterTable {
             ClientChangesImpl cs = new ClientChangesImpl(session);
             if (session.clientChanges == null)
                 session.clientChanges = cs;
+            //printMaps("refresh");
             for (int i=0; i<clusterUID.length; ++i) {
                 try {
                     if (DebugPolicy.REPORT_CLUSTER_EVENTS)
@@ -739,6 +769,8 @@ public final class ClusterTable implements IClusterTable {
                     Logger.defaultLogError("Failed to load cluster in refresh.", t);
                 }
             }
+            if (VALIDATE_SIZE)
+                validateSize("refresh");
             // Fake update of cluster changes.
             QueryProcessor queryProcessor = session.getQueryProvider2();
             WriteGraphImpl writer = WriteGraphImpl.create(queryProcessor, session.writeSupport, null);
@@ -756,6 +788,7 @@ public final class ClusterTable implements IClusterTable {
                 } finally {
                     if (null != th)
                         session.writeState = null;
+                    cs.dispose();
                 }
             }
         }
@@ -793,11 +826,13 @@ public final class ClusterTable implements IClusterTable {
                 System.err.println("value " + cc.getValueIndex()[i] + " changed.");
         }
     }
-    final void refreshImportance(ClusterImpl c) {
+    final synchronized void refreshImportance(ClusterImpl c) {
 
         if (c.isWriteOnly())
             return;
 
+        //printMaps("refreshImportance");
+
         importanceMap.remove(c.getImportance());
         if(collectorPolicy != null) collectorPolicy.removed(c);
 
@@ -809,6 +844,8 @@ public final class ClusterTable implements IClusterTable {
 
         importanceMap.put(c.getImportance(), new ImportanceEntry(c));
         if(collectorPolicy != null) collectorPolicy.added(c);
+        if (VALIDATE_SIZE)
+            validateSize("refreshImportance");
 
     }
 
@@ -863,7 +900,7 @@ public final class ClusterTable implements IClusterTable {
     }
     
     @SuppressWarnings("unchecked")
-    public final <T extends ClusterI> T getClusterByResourceKey(final int resourceKey) {
+    public synchronized final <T extends ClusterI> T getClusterByResourceKey(final int resourceKey) {
         int clusterKey = ClusterTraitsBase.getClusterKeyFromResourceKeyNoThrow(resourceKey);
         if (ClusterTraitsBase.isVirtualClusterKey(clusterKey))
             throw new RuntimeException("Tried to get a persistent cluster for a virtual resource.");
@@ -1127,7 +1164,7 @@ public final class ClusterTable implements IClusterTable {
     }
 
     public long timeCounter() {
-        return timeCounter++;
+        return timeCounter.getAndIncrement();
     }
 
     public boolean hasVirtual(int index) {
@@ -1175,12 +1212,15 @@ public final class ClusterTable implements IClusterTable {
         }
     }
 
-    private void validateSize() {
+    private void validateSize(String place) {
         if (!VALIDATE_SIZE)
             return;
 
-//        System.out.println("validating cached cluster sizes: " + sizeInBytes + ", hashMap.size="
-//                + clusters.hashMap.size() + ", importanceMap.size=" + importanceMap.size());
+        int ims = importanceMap.size();
+        int ihms = countImportantClusters();
+
+//        System.out.format("[ClusterTable.%s] Validating: byteSize=%d (%d MB), hashMap=%d/%d, importanceMap=%d%n",
+//                place, sizeInBytes, sizeInBytes / (1024*1024), ihms, clusters.hashMap.size(), ims);
 
         int i = clusterArray.length;
         long size = 0;
@@ -1195,19 +1235,43 @@ public final class ClusterTable implements IClusterTable {
                 System.out.println("BUG: CACHED CLUSTER SIZE DIFFERS FROM CALCULATED: " + sizeInBytes + " != " + size + ", delta = " + (sizeInBytes - size));
             //else System.out.println("\"BUG?\": SIZES DIFFER: " + sizeInBytes + " != " + size + ", delta = " + (sizeInBytes - size));
         }
+        if (ims != ihms) {
+            System.out.println("BUG2: hashmap and importanceMap sizes differ: " + ihms + " != " + ims + ", delta=" + (ihms - ims));
+            printMaps("validateSize");
+        }
+        //System.out.println("[" + place + "] VALIDATED");
+    }
 
-        int ims = importanceMap.size();
-        int[] hms = {0};
+    private void printMaps(String place) {
+        int ihms = countImportantClusters();
+        System.out.println("## printMaps(" + place + ") - " + importanceMap.size() + " - (" + ihms + "/" + clusters.hashMap.size() + ")");
+        System.out.println("importanceMap (" + importanceMap.size() + "):");
+        importanceMap.forEach((importance, ie) -> {
+            System.out.format("\t%d: %s%n", importance, ie.toString());
+        });
+        System.out.println("clusters.hashMap (" + ihms + "/" + clusters.hashMap.size() + "):");
         clusters.hashMap.forEachEntry((cid, c) -> {
-            if (c != null && !c.isWriteOnly() && !c.isEmpty() && c.isLoaded()) {
-                //System.out.println(cid + ": " + c);
-                hms[0]++;
-            }
+            boolean important = importantCluster(c);
+            boolean wo = c != null && c.isWriteOnly();
+            boolean empty = c != null && c.isEmpty();
+            boolean loaded = c != null && c.isLoaded();
+            System.out.format("\t%s: %d - %s (writeOnly=%b, empty=%b, loaded=%b)%n", important ? " I" : "NI", cid, c, wo, empty, loaded);
             return true;
         });
-        if (Math.abs(ims-hms[0]) > 0) {
-            System.out.println("BUG2: hashmap and importanceMap sizes differ: " + hms[0] + " != " + ims + ", delta=" + (hms[0] - ims));
-        }
+    }
+
+    private int countImportantClusters() {
+        int[] result = { 0 };
+        clusters.hashMap.forEachEntry((cid, c) -> {
+            if (importantCluster(c))
+                result[0]++;
+            return true;
+        });
+        return result[0];
+    }
+
+    private static boolean importantCluster(ClusterImpl c) {
+        return c != null && !c.isWriteOnly() && c.isLoaded();// && !c.isEmpty();
     }
 
 }