1 package org.simantics.db.impl.query;
3 import org.simantics.db.impl.query.QueryProcessor.QueryCollectorSupport;
5 class QueryCollectorImpl implements QueryProcessor.QueryCollector {
7 private static final boolean DEBUG = false;
8 private static final boolean DEBUG_STATUS = false;
10 private final QueryProcessor queryProcessor;
12 final private QueryCollectorSupport support;
15 * Set to true: at end of iteration if moreAll is false
16 * Set to false: upon gc start and whenever a prospect is added.
19 boolean doneAll = false;
21 * Set to true: upon gc start and whenever a prospect is added.
22 * Set to false: at end of entry iteration
23 * => if this is already false at end of entry iteration => no more work to be done
28 * Change propagation is in progress
30 boolean propagate = true;
33 private static final int COLLECT_N = 1000;
35 private long spent = 0;
37 QueryCollectorImpl(QueryProcessor queryProcessor, QueryCollectorSupport support) {
38 this.queryProcessor = queryProcessor;
39 this.support = support;
43 public void collect(int youngTarget, int allowedTimeInMs) {
45 // Flush listener registrations to prevent the collector from trashing
46 // listeners that are still queued up waiting to be registered.
47 queryProcessor.listening.sync();
49 long start = System.nanoTime();
51 // Refresh current size
52 int size = support.calculateCurrentSize();
53 int bound = queryProcessor.boundQueries;
54 int young = size - bound;
55 int youngPct = size > 0 ? 100*young / size : 0;
57 // Initialize support for new run
58 // If support returns 0 we are starting from 0
59 if(support.start(youngTarget == 0)) {
63 // We monitor all prospects here
64 CacheEntryBase prospect = support.iterate(0);
65 while(prospect != null) {
66 if(prospect.isDiscarded()) {
70 CacheEntry parent = prospect.getFirstParent(queryProcessor);
74 support.setLevel(prospect, parent.getLevel() + 1);
77 prospect = support.iterate(0);
80 // If no prospects were collected and most of the queries are old we can stop here
81 if(!propagate && youngPct < youngTarget) {
82 // System.err.println("collect2 skipped");
83 // System.err.println("-size=" + size);
84 // System.err.println("-young=" + young);
90 long test = (long)allowedTimeInMs*1000000;
96 size = support.getCurrentSize();
97 bound = queryProcessor.boundQueries;
99 long elapsed = System.nanoTime()-start;
100 boolean timeCondition = elapsed > test;
102 if(doneAll || timeCondition) {
107 System.err.println("Query collector used " + 1e-9*elapsed + "s total queries: " + size + " bound queries: " + bound + " spent: " + (double)spent*1e-9);
113 // Iterate all entries and update sets
115 // long start2 = System.nanoTime();
116 for(int i=0;i<COLLECT_N;i++) {
117 CacheEntryBase entry = support.iterate(Integer.MAX_VALUE);
120 System.err.println("finished iteration");
121 System.err.println("-moreAll=" + moreAll);
131 CacheEntry parent = entry.getFirstParent(queryProcessor);
134 boolean collected = tryCollect(entry);
136 entry.setLevel((short)0);
141 parent = entry.pruneFirstParents();
144 boolean collected = tryCollect(entry);
146 entry.setLevel((short)0);
151 entry.pruneParentSet();
152 support.setLevel(entry, parent.getLevel() + 1);
158 int status = entry.getGCStatus();
159 if((status & CacheEntry.HAS_BEEN_BOUND) == 0) {
161 if(parent != null && !parent.isDiscarded()) {
162 if((parent.getGCStatus() & CacheEntry.HAS_BEEN_BOUND) != 0) {
163 queryProcessor.boundQueries++;
164 entry.setGCStatusFlag(CacheEntry.HAS_BEEN_BOUND, true);
168 if(queryProcessor.listening.hasListenerAfterDisposing(entry)) {
169 if((status & CacheEntry.HAS_BEEN_BOUND) == 0) {
170 queryProcessor.boundQueries++;
171 entry.setGCStatusFlag(CacheEntry.HAS_BEEN_BOUND, true);
183 private boolean tryCollect(CacheEntry entry) {
184 if (!queryProcessor.listening.hasListenerAfterDisposing(entry))
185 if(entry.shouldBeCollected()) {
186 queryProcessor.removeQuery(entry);
196 private void start() {