1 package org.simantics.db.impl.query;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.IdentityHashMap;
9 import org.simantics.databoard.Bindings;
10 import org.simantics.databoard.util.IdentityHashSet;
11 import org.simantics.db.DevelopmentKeys;
12 import org.simantics.db.common.exception.DebugException;
13 import org.simantics.db.impl.query.QueryProcessor.QueryCollectorSupport;
14 import org.simantics.utils.Development;
16 class QueryCollectorImpl2 implements QueryProcessor.QueryCollector {
18 private final QueryProcessor queryProcessor;
20 final private QueryCollectorSupport support;
22 private int lastKnownFixedSize = 0;
24 QueryCollectorImpl2(QueryProcessor queryProcessor, QueryCollectorSupport support) {
25 this.queryProcessor = queryProcessor;
26 this.support = support;
29 private boolean findCollectables(CacheEntry<?> entry, Map<CacheEntry, Boolean> collectables, ArrayList<CacheEntry> result) {
31 if (entry.isDiscarded()) {
32 if (Development.DEVELOPMENT) {
33 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
34 System.err.println("GC: discarded entry " + entry);
40 if (entry.isPending()) {
41 if (Development.DEVELOPMENT) {
42 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
43 System.err.println("GC: pending entry " + entry + " was not collected.");
46 collectables.remove(entry);
50 if (this.queryProcessor.listening.hasListenerAfterDisposing(entry)) {
51 if (Development.DEVELOPMENT) {
52 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
53 System.err.println("GC: listened entry " + entry + " was not collected. Entry=" + entry);
56 collectables.remove(entry);
60 for (CacheEntry parent : entry.getParents(queryProcessor)) {
62 boolean parentIsCollectable = false;
64 if (!collectables.containsKey(parent)) {
65 collectables.put(parent, true);
66 parentIsCollectable = findCollectables(parent, collectables, result);
68 parentIsCollectable = collectables.get(parent);
71 if(!parentIsCollectable) {
72 if (Development.DEVELOPMENT) {
73 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
74 System.err.println("GC: due to bound parent " + parent + " the entry + " + entry + " was not collected.");
77 collectables.remove(entry);
83 if(entry.shouldBeCollected()) {
84 // This can be collected
93 private List<CacheEntry> findCollectables() {
95 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
97 IdentityHashMap<CacheEntry, Boolean> collectables = new IdentityHashMap<CacheEntry, Boolean>();
98 Collection<CacheEntry> rootList = support.getRootList();
99 for (CacheEntry entry : rootList) {
100 if(!collectables.containsKey(entry)) {
101 collectables.put(entry, true);
102 findCollectables(entry, collectables, result);
106 if(Development.DEVELOPMENT) {
107 IdentityHashSet<CacheEntry> set = new IdentityHashSet<CacheEntry>();
108 for(CacheEntry entry : result) {
109 if(!set.add(entry)) throw new IllegalStateException();
117 private void doCollect(int currentSize, int maxNumberOfCollectableQueries) {
119 List<CacheEntry> collectables = findCollectables();
121 // Compute amount of free queries
122 int freeCount = collectables.size();
124 if (Development.DEVELOPMENT) {
125 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
126 System.err.println("collector found " + freeCount + " free queries.");
130 lastKnownFixedSize = currentSize - freeCount;
132 // No need to collect
133 if(freeCount < maxNumberOfCollectableQueries) return;
135 int target = freeCount - maxNumberOfCollectableQueries/2;
138 if (Development.DEVELOPMENT) {
139 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
140 System.err.println("collector found " + freeCount + " free queries.");
141 System.err.println("collector removes " + target + " free queries.");
145 for(CacheEntry entry : collectables) {
146 if(queryProcessor.removeQuery(entry))
147 if(--target < 0) break;
150 // Prune discarded parents
151 ArrayList<CacheEntry> removals = new ArrayList<CacheEntry>();
152 for (CacheEntry<?> entry : support.allCaches().toCollection()) {
153 for(CacheEntry p : entry.getParents(queryProcessor)) {
154 if(p.isDiscarded()) removals.add(p);
156 for(CacheEntry r : removals) {
157 entry.removeParent(r);
163 if (Development.DEVELOPMENT) {
164 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
165 System.err.println("collect found " + freeCount + " collectable entries.");
174 public void collect(int youngTarget, int maxAllowedTimeInMs) {
179 int current = support.calculateCurrentSize();
181 if (Development.DEVELOPMENT) {
182 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
183 new DebugException("checking the need for collecting queries (current=" + current + " , lastKnownFixedSize=" + lastKnownFixedSize + " max free=" + 0 + ")").printStackTrace();
187 queryProcessor.cache.collecting = true;
189 long start = System.nanoTime();
191 doCollect(current, 0);
193 if (Development.DEVELOPMENT) {
194 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
195 System.err.println("collect finished with " + support.calculateCurrentSize() + " entries (lastKnownFixedSize=" + lastKnownFixedSize + ").");
199 long duration = System.nanoTime() - start;
201 if (Development.DEVELOPMENT) {
202 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYCOLLECTOR, Bindings.BOOLEAN)) {
203 System.err.println("Collect took " + 1e-9*duration + "s.");
207 } catch (Throwable t) {
211 queryProcessor.cache.collecting = false;