X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.db.impl%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fimpl%2Fquery%2FQueryCollectorImpl2.java;fp=bundles%2Forg.simantics.db.impl%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fimpl%2Fquery%2FQueryCollectorImpl2.java;h=b964854b77465bf8752d25b4cfa9473e1db385fd;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl2.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl2.java new file mode 100644 index 000000000..b964854b7 --- /dev/null +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl2.java @@ -0,0 +1,184 @@ +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.util.IdentityHashSet; +import org.simantics.db.common.exception.DebugException; +import org.simantics.db.impl.DebugPolicy; +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 collectables, ArrayList result) { + + if (entry.isDiscarded()) { + if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE) + System.out.println("GC: discarded entry " + entry); + return true; + } + + if (entry.isPending()) { + if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE) + System.out.println("GC: pending entry " + entry + " was not collected."); + collectables.remove(entry); + return false; + } + + if (this.queryProcessor.hasListenerAfterDisposing(entry)) { + if (DebugPolicy.COLLECT && DebugPolicy.VERBOSE) { + System.out.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(DebugPolicy.COLLECT && DebugPolicy.VERBOSE) + System.out.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 findCollectables() { + + ArrayList result = new ArrayList(); + + IdentityHashMap collectables = new IdentityHashMap(); + Collection rootList = support.getRootList(); + for (CacheEntry entry : rootList) { + if(!collectables.containsKey(entry)) { + collectables.put(entry, true); + findCollectables(entry, collectables, result); + } + } + + if(Development.DEVELOPMENT) { + IdentityHashSet set = new IdentityHashSet(); + for(CacheEntry entry : result) { + if(!set.add(entry)) throw new IllegalStateException(); + } + } + + return result; + + } + + private void doCollect(int currentSize, int maxNumberOfCollectableQueries) { + + List collectables = findCollectables(); + + // Compute amount of free queries + int freeCount = collectables.size(); + + if(DebugPolicy.COLLECT) + System.out.println("collector found " + freeCount + " free queries."); + + lastKnownFixedSize = currentSize - freeCount; + + // No need to collect + if(freeCount < maxNumberOfCollectableQueries) return; + + int target = freeCount - maxNumberOfCollectableQueries/2; + + if(DebugPolicy.COLLECT) + System.out.println("collector removes " + target + " free queries."); + + for(CacheEntry entry : collectables) { + if(queryProcessor.removeQuery(entry)) + if(--target < 0) break; + } + + // Prune discarded parents + ArrayList removals = new ArrayList(); + 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(DebugPolicy.COLLECT) { + System.out.println("collect found " + freeCount + " collectable entries."); + } + + return; + + } + + @Override + public void collect(int youngTarget, int maxAllowedTimeInMs) { + + try { + + int current = support.calculateCurrentSize(); + + if(DebugPolicy.COLLECT) + new DebugException("checking the need for collecting queries (current=" + current + " , lastKnownFixedSize=" + lastKnownFixedSize + " max free=" + 0 + ")").printStackTrace(); + + QueryProcessor.collecting = true; + + long start = System.nanoTime(); + + doCollect(current, 0); + + if(DebugPolicy.COLLECT) + System.out.println("collect finished with " + support.calculateCurrentSize() + " entries (lastKnownFixedSize=" + lastKnownFixedSize + ")."); + + long duration = System.nanoTime() - start; + + if(DebugPolicy.COLLECT) + System.err.println("Collect took " + 1e-9*duration + "s."); + + } catch (Throwable t) { + t.printStackTrace(); + } + + QueryProcessor.collecting = false; + + + } + + +} \ No newline at end of file