--- /dev/null
+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
+}
\ No newline at end of file