]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl2.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / QueryCollectorImpl2.java
index b964854b77465bf8752d25b4cfa9473e1db385fd..b0e6330700e2fd587d9aa873a0446671ddd1f77d 100644 (file)
-package org.simantics.db.impl.query;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.IdentityHashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-\r
-import org.simantics.databoard.util.IdentityHashSet;\r
-import org.simantics.db.common.exception.DebugException;\r
-import org.simantics.db.impl.DebugPolicy;\r
-import org.simantics.db.impl.query.QueryProcessor.QueryCollectorSupport;\r
-import org.simantics.utils.Development;\r
-\r
-class QueryCollectorImpl2 implements QueryProcessor.QueryCollector {\r
-\r
-       private final QueryProcessor queryProcessor;\r
-\r
-       final private QueryCollectorSupport support;\r
-\r
-       private int lastKnownFixedSize = 0;\r
-\r
-       QueryCollectorImpl2(QueryProcessor queryProcessor, QueryCollectorSupport support) {\r
-               this.queryProcessor = queryProcessor;\r
-               this.support = support;\r
-       }\r
-\r
-       private boolean findCollectables(CacheEntry entry, Map<CacheEntry, Boolean> collectables, ArrayList<CacheEntry> result) {\r
-\r
-               if (entry.isDiscarded()) {\r
-                       if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)\r
-                               System.out.println("GC: discarded entry " + entry);\r
-                       return true;\r
-               }\r
-\r
-               if (entry.isPending()) {\r
-                       if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)\r
-                               System.out.println("GC: pending entry " + entry + " was not collected.");\r
-                       collectables.remove(entry);\r
-                       return false;\r
-               }\r
-\r
-               if (this.queryProcessor.hasListenerAfterDisposing(entry)) {\r
-                       if (DebugPolicy.COLLECT && DebugPolicy.VERBOSE) {\r
-                               System.out.println("GC: listened entry " + entry + " was not collected. Entry=" + entry);\r
-                       }\r
-                       collectables.remove(entry);\r
-                       return false;\r
-               }\r
-\r
-               for (CacheEntry parent : entry.getParents(queryProcessor)) {\r
-\r
-                       boolean parentIsCollectable = false;\r
-\r
-                       if (!collectables.containsKey(parent)) {\r
-                               collectables.put(parent, true);\r
-                               parentIsCollectable = findCollectables(parent, collectables, result);\r
-                       } else {\r
-                               parentIsCollectable = collectables.get(parent);\r
-                       }\r
-\r
-                       if(!parentIsCollectable) {\r
-                               if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)\r
-                                       System.out.println("GC: due to bound parent " + parent + " the entry + " + entry + " was not collected.");\r
-                               collectables.remove(entry);\r
-                               return false;\r
-                       }\r
-\r
-               }\r
-\r
-               if(entry.shouldBeCollected()) {\r
-                       // This can be collected\r
-                       result.add(entry);\r
-                       return true;\r
-               } else {\r
-                       return false;\r
-               }\r
-\r
-       }\r
-\r
-       private List<CacheEntry> findCollectables() {\r
-\r
-               ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();\r
-\r
-               IdentityHashMap<CacheEntry, Boolean> collectables = new IdentityHashMap<CacheEntry, Boolean>();\r
-               Collection<CacheEntry> rootList = support.getRootList();\r
-               for (CacheEntry entry : rootList) {\r
-                       if(!collectables.containsKey(entry)) {\r
-                               collectables.put(entry, true);\r
-                               findCollectables(entry, collectables, result);\r
-                       }\r
-               }\r
-\r
-               if(Development.DEVELOPMENT) {\r
-                       IdentityHashSet<CacheEntry> set = new IdentityHashSet<CacheEntry>();\r
-                       for(CacheEntry entry : result) {\r
-                               if(!set.add(entry)) throw new IllegalStateException();\r
-                       }\r
-               }\r
-\r
-               return result;\r
-\r
-       }\r
-\r
-       private void doCollect(int currentSize, int maxNumberOfCollectableQueries) {\r
-\r
-               List<CacheEntry> collectables = findCollectables();\r
-\r
-               // Compute amount of free queries\r
-               int freeCount = collectables.size();\r
-\r
-               if(DebugPolicy.COLLECT)\r
-                       System.out.println("collector found " + freeCount + " free queries.");\r
-\r
-               lastKnownFixedSize = currentSize - freeCount;\r
-\r
-               // No need to collect\r
-               if(freeCount < maxNumberOfCollectableQueries) return;\r
-\r
-               int target = freeCount - maxNumberOfCollectableQueries/2;\r
-\r
-               if(DebugPolicy.COLLECT)\r
-                       System.out.println("collector removes " + target + " free queries.");\r
-\r
-               for(CacheEntry entry : collectables) {\r
-                       if(queryProcessor.removeQuery(entry))\r
-                               if(--target < 0) break;\r
-               }\r
-\r
-               // Prune discarded parents\r
-               ArrayList<CacheEntry> removals = new ArrayList<CacheEntry>();\r
-               for (CacheEntry entry : support.allCaches().toCollection()) {\r
-                       for(CacheEntry p : entry.getParents(queryProcessor)) {\r
-                               if(p.isDiscarded()) removals.add(p);\r
-                       }\r
-                       for(CacheEntry r : removals) {\r
-                               entry.removeParent(r);\r
-                       }\r
-                       removals.clear();\r
-               }\r
-\r
-               if(DebugPolicy.COLLECT) {\r
-                       System.out.println("collect found " + freeCount + " collectable entries.");\r
-               }\r
-\r
-               return;\r
-\r
-       }\r
-\r
-       @Override\r
-       public void collect(int youngTarget, int maxAllowedTimeInMs) {\r
-\r
-               try {\r
-\r
-                       int current = support.calculateCurrentSize();\r
-\r
-                       if(DebugPolicy.COLLECT)\r
-                               new DebugException("checking the need for collecting queries (current=" + current + " , lastKnownFixedSize=" + lastKnownFixedSize + " max free=" + 0 + ")").printStackTrace();\r
-\r
-                       QueryProcessor.collecting = true;\r
-\r
-                       long start = System.nanoTime();\r
-\r
-                       doCollect(current, 0);\r
-\r
-                       if(DebugPolicy.COLLECT)\r
-                               System.out.println("collect finished with " + support.calculateCurrentSize() + " entries (lastKnownFixedSize=" + lastKnownFixedSize + ").");\r
-\r
-                       long duration = System.nanoTime() - start;\r
-\r
-                       if(DebugPolicy.COLLECT)\r
-                               System.err.println("Collect took " + 1e-9*duration + "s.");\r
-\r
-               } catch (Throwable t) {\r
-                       t.printStackTrace();\r
-               }\r
-\r
-               QueryProcessor.collecting = false;\r
-\r
-\r
-       }\r
-\r
-\r
+package org.simantics.db.impl.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.util.IdentityHashSet;
+import org.simantics.db.DevelopmentKeys;
+import org.simantics.db.common.exception.DebugException;
+import org.simantics.db.impl.query.QueryProcessor.QueryCollectorSupport;
+import org.simantics.utils.Development;
+
+class QueryCollectorImpl2 implements QueryProcessor.QueryCollector {
+
+       private final QueryProcessor queryProcessor;
+
+       final private QueryCollectorSupport support;
+
+       private int lastKnownFixedSize = 0;
+
+       QueryCollectorImpl2(QueryProcessor queryProcessor, QueryCollectorSupport support) {
+               this.queryProcessor = queryProcessor;
+               this.support = support;
+       }
+
+       private boolean findCollectables(CacheEntry<?> entry, Map<CacheEntry, Boolean> collectables, ArrayList<CacheEntry> result) {
+
+               if (entry.isDiscarded()) {
+                       if (Development.DEVELOPMENT) {
+                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                                       System.err.println("GC: discarded entry " + entry);
+                               }
+                       }
+                       return true;
+               }
+
+               if (entry.isPending()) {
+                       if (Development.DEVELOPMENT) {
+                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                                       System.err.println("GC: pending entry " + entry + " was not collected.");
+                               }
+                       }
+                       collectables.remove(entry);
+                       return false;
+               }
+
+               if (this.queryProcessor.listening.hasListenerAfterDisposing(entry)) {
+                       if (Development.DEVELOPMENT) {
+                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                                       System.err.println("GC: listened entry " + entry + " was not collected. Entry=" + entry);
+                               }
+                       }
+                       collectables.remove(entry);
+                       return false;
+               }
+
+               for (CacheEntry parent : entry.getParents(queryProcessor)) {
+
+                       boolean parentIsCollectable = false;
+
+                       if (!collectables.containsKey(parent)) {
+                               collectables.put(parent, true);
+                               parentIsCollectable = findCollectables(parent, collectables, result);
+                       } else {
+                               parentIsCollectable = collectables.get(parent);
+                       }
+
+                       if(!parentIsCollectable) {
+                               if (Development.DEVELOPMENT) {
+                                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                                               System.err.println("GC: due to bound parent " + parent + " the entry + " + entry + " was not collected.");
+                                       }
+                               }
+                               collectables.remove(entry);
+                               return false;
+                       }
+
+               }
+
+               if(entry.shouldBeCollected()) {
+                       // This can be collected
+                       result.add(entry);
+                       return true;
+               } else {
+                       return false;
+               }
+
+       }
+
+       private List<CacheEntry> findCollectables() {
+
+               ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
+
+               IdentityHashMap<CacheEntry, Boolean> collectables = new IdentityHashMap<CacheEntry, Boolean>();
+               Collection<CacheEntry> rootList = support.getRootList();
+               for (CacheEntry entry : rootList) {
+                       if(!collectables.containsKey(entry)) {
+                               collectables.put(entry, true);
+                               findCollectables(entry, collectables, result);
+                       }
+               }
+
+               if(Development.DEVELOPMENT) {
+                       IdentityHashSet<CacheEntry> set = new IdentityHashSet<CacheEntry>();
+                       for(CacheEntry entry : result) {
+                               if(!set.add(entry)) throw new IllegalStateException();
+                       }
+               }
+
+               return result;
+
+       }
+
+       private void doCollect(int currentSize, int maxNumberOfCollectableQueries) {
+
+               List<CacheEntry> collectables = findCollectables();
+
+               // Compute amount of free queries
+               int freeCount = collectables.size();
+
+               if (Development.DEVELOPMENT) {
+                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                               System.err.println("collector found " + freeCount + " free queries.");
+                       }
+               }
+
+               lastKnownFixedSize = currentSize - freeCount;
+
+               // No need to collect
+               if(freeCount < maxNumberOfCollectableQueries) return;
+
+               int target = freeCount - maxNumberOfCollectableQueries/2;
+
+               
+               if (Development.DEVELOPMENT) {
+                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                               System.err.println("collector found " + freeCount + " free queries.");
+                               System.err.println("collector removes " + target + " free queries.");
+                       }
+               }
+
+               for(CacheEntry entry : collectables) {
+                       if(queryProcessor.removeQuery(entry))
+                               if(--target < 0) break;
+               }
+
+               // Prune discarded parents
+               ArrayList<CacheEntry> removals = new ArrayList<CacheEntry>();
+               for (CacheEntry<?> entry : support.allCaches().toCollection()) {
+                       for(CacheEntry p : entry.getParents(queryProcessor)) {
+                               if(p.isDiscarded()) removals.add(p);
+                       }
+                       for(CacheEntry r : removals) {
+                               entry.removeParent(r);
+                       }
+                       removals.clear();
+               }
+
+               
+               if (Development.DEVELOPMENT) {
+                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                               System.err.println("collect found " + freeCount + " collectable entries.");
+                       }
+               }
+
+               return;
+
+       }
+
+       @Override
+       public void collect(int youngTarget, int maxAllowedTimeInMs) {
+
+               try {
+
+
+                       int current = support.calculateCurrentSize();
+
+                       if (Development.DEVELOPMENT) {
+                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                                       new DebugException("checking the need for collecting queries (current=" + current + " , lastKnownFixedSize=" + lastKnownFixedSize + " max free=" + 0 + ")").printStackTrace();
+                               }
+                       }
+                       
+                       queryProcessor.cache.collecting = true;
+
+                       long start = System.nanoTime();
+
+                       doCollect(current, 0);
+
+                       if (Development.DEVELOPMENT) {
+                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                                       System.err.println("collect finished with " + support.calculateCurrentSize() + " entries (lastKnownFixedSize=" + lastKnownFixedSize + ").");
+                               }
+                       }
+
+                       long duration = System.nanoTime() - start;
+
+                       if (Development.DEVELOPMENT) {
+                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
+                                       System.err.println("Collect took " + 1e-9*duration + "s.");
+                               }
+                       }
+
+               } catch (Throwable t) {
+                       t.printStackTrace();
+               }
+
+               queryProcessor.cache.collecting = false;
+
+       }
+
+
 }
\ No newline at end of file