-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;
+
+ }
+
+