1 package org.simantics.db.impl.query;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Collection;
\r
5 import java.util.IdentityHashMap;
\r
6 import java.util.List;
\r
7 import java.util.Map;
\r
9 import org.simantics.databoard.util.IdentityHashSet;
\r
10 import org.simantics.db.common.exception.DebugException;
\r
11 import org.simantics.db.impl.DebugPolicy;
\r
12 import org.simantics.db.impl.query.QueryProcessor.QueryCollectorSupport;
\r
13 import org.simantics.utils.Development;
\r
15 class QueryCollectorImpl2 implements QueryProcessor.QueryCollector {
\r
17 private final QueryProcessor queryProcessor;
\r
19 final private QueryCollectorSupport support;
\r
21 private int lastKnownFixedSize = 0;
\r
23 QueryCollectorImpl2(QueryProcessor queryProcessor, QueryCollectorSupport support) {
\r
24 this.queryProcessor = queryProcessor;
\r
25 this.support = support;
\r
28 private boolean findCollectables(CacheEntry entry, Map<CacheEntry, Boolean> collectables, ArrayList<CacheEntry> result) {
\r
30 if (entry.isDiscarded()) {
\r
31 if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)
\r
32 System.out.println("GC: discarded entry " + entry);
\r
36 if (entry.isPending()) {
\r
37 if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)
\r
38 System.out.println("GC: pending entry " + entry + " was not collected.");
\r
39 collectables.remove(entry);
\r
43 if (this.queryProcessor.hasListenerAfterDisposing(entry)) {
\r
44 if (DebugPolicy.COLLECT && DebugPolicy.VERBOSE) {
\r
45 System.out.println("GC: listened entry " + entry + " was not collected. Entry=" + entry);
\r
47 collectables.remove(entry);
\r
51 for (CacheEntry parent : entry.getParents(queryProcessor)) {
\r
53 boolean parentIsCollectable = false;
\r
55 if (!collectables.containsKey(parent)) {
\r
56 collectables.put(parent, true);
\r
57 parentIsCollectable = findCollectables(parent, collectables, result);
\r
59 parentIsCollectable = collectables.get(parent);
\r
62 if(!parentIsCollectable) {
\r
63 if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)
\r
64 System.out.println("GC: due to bound parent " + parent + " the entry + " + entry + " was not collected.");
\r
65 collectables.remove(entry);
\r
71 if(entry.shouldBeCollected()) {
\r
72 // This can be collected
\r
81 private List<CacheEntry> findCollectables() {
\r
83 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
\r
85 IdentityHashMap<CacheEntry, Boolean> collectables = new IdentityHashMap<CacheEntry, Boolean>();
\r
86 Collection<CacheEntry> rootList = support.getRootList();
\r
87 for (CacheEntry entry : rootList) {
\r
88 if(!collectables.containsKey(entry)) {
\r
89 collectables.put(entry, true);
\r
90 findCollectables(entry, collectables, result);
\r
94 if(Development.DEVELOPMENT) {
\r
95 IdentityHashSet<CacheEntry> set = new IdentityHashSet<CacheEntry>();
\r
96 for(CacheEntry entry : result) {
\r
97 if(!set.add(entry)) throw new IllegalStateException();
\r
105 private void doCollect(int currentSize, int maxNumberOfCollectableQueries) {
\r
107 List<CacheEntry> collectables = findCollectables();
\r
109 // Compute amount of free queries
\r
110 int freeCount = collectables.size();
\r
112 if(DebugPolicy.COLLECT)
\r
113 System.out.println("collector found " + freeCount + " free queries.");
\r
115 lastKnownFixedSize = currentSize - freeCount;
\r
117 // No need to collect
\r
118 if(freeCount < maxNumberOfCollectableQueries) return;
\r
120 int target = freeCount - maxNumberOfCollectableQueries/2;
\r
122 if(DebugPolicy.COLLECT)
\r
123 System.out.println("collector removes " + target + " free queries.");
\r
125 for(CacheEntry entry : collectables) {
\r
126 if(queryProcessor.removeQuery(entry))
\r
127 if(--target < 0) break;
\r
130 // Prune discarded parents
\r
131 ArrayList<CacheEntry> removals = new ArrayList<CacheEntry>();
\r
132 for (CacheEntry entry : support.allCaches().toCollection()) {
\r
133 for(CacheEntry p : entry.getParents(queryProcessor)) {
\r
134 if(p.isDiscarded()) removals.add(p);
\r
136 for(CacheEntry r : removals) {
\r
137 entry.removeParent(r);
\r
142 if(DebugPolicy.COLLECT) {
\r
143 System.out.println("collect found " + freeCount + " collectable entries.");
\r
151 public void collect(int youngTarget, int maxAllowedTimeInMs) {
\r
155 int current = support.calculateCurrentSize();
\r
157 if(DebugPolicy.COLLECT)
\r
158 new DebugException("checking the need for collecting queries (current=" + current + " , lastKnownFixedSize=" + lastKnownFixedSize + " max free=" + 0 + ")").printStackTrace();
\r
160 QueryProcessor.collecting = true;
\r
162 long start = System.nanoTime();
\r
164 doCollect(current, 0);
\r
166 if(DebugPolicy.COLLECT)
\r
167 System.out.println("collect finished with " + support.calculateCurrentSize() + " entries (lastKnownFixedSize=" + lastKnownFixedSize + ").");
\r
169 long duration = System.nanoTime() - start;
\r
171 if(DebugPolicy.COLLECT)
\r
172 System.err.println("Collect took " + 1e-9*duration + "s.");
\r
174 } catch (Throwable t) {
\r
175 t.printStackTrace();
\r
178 QueryProcessor.collecting = false;
\r