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;
32 private static final int COLLECT_N = 1000;
34 private long allowance = 100;
35 private long spent = 0;
36 private long collectionCounter = 0;
38 QueryCollectorImpl(QueryProcessor queryProcessor, QueryCollectorSupport support) {
39 this.queryProcessor = queryProcessor;
40 this.support = support;
44 public void collect(int youngTarget, int allowedTimeInMs) {
46 long start = System.nanoTime();
48 // Refresh current size
49 int size = support.calculateCurrentSize();
51 // if(collectionCounter > allowance) {
52 // collectionCounter = 0;
53 // allowance = (allowance * 1100) / 1000;
56 int bound = queryProcessor.boundQueries;
57 int young = size - bound;
58 int youngPct = size > 0 ? 100*young / size : 0;
60 // System.err.println("Collect size = " + size + " bound=" + bound + " allowance=" + allowance);
62 // Allowance maintains a reasonable set of queries
63 if(size < allowance) return;
65 // No need to collect anything if the amount of free queries is small compared to the amount of bound queries
66 if(youngPct < youngTarget) return;
68 // Initialize support for new run
69 // If support returns 0 we are starting from 0
70 if(support.start(youngTarget == 0)) {
74 // We monitor all prospects here
75 CacheEntryBase prospect = support.iterate(0);
76 while(prospect != null) {
77 if(prospect.isDiscarded()) {
81 CacheEntry parent = prospect.getFirstParent(queryProcessor);
85 support.setLevel(prospect, parent.getLevel() + 1);
88 prospect = support.iterate(0);
91 // If no prospects were collected and most of the queries are old we can stop here
92 if(!propagate && youngPct < youngTarget) {
93 // System.err.println("collect2 skipped");
94 // System.err.println("-size=" + size);
95 // System.err.println("-young=" + young);
101 long test = (long)allowedTimeInMs*1000000;
107 size = support.getCurrentSize();
108 bound = queryProcessor.boundQueries;
110 long elapsed = System.nanoTime()-start;
111 boolean timeCondition = elapsed > test;
113 if(doneAll || timeCondition) {
118 System.err.println("Query collector used " + 1e-9*elapsed + "s total queries: " + size + " bound queries: " + bound + " spent: " + (double)spent*1e-9);
124 // Iterate all entries and update sets
126 // long start2 = System.nanoTime();
127 for(int i=0;i<COLLECT_N;i++) {
128 CacheEntryBase entry = support.iterate(Integer.MAX_VALUE);
131 System.err.println("finished iteration");
132 System.err.println("-moreAll=" + moreAll);
142 CacheEntry parent = entry.getFirstParent(queryProcessor);
145 boolean collected = tryCollect(entry);
147 entry.setLevel((short)0);
152 parent = entry.pruneFirstParents();
155 boolean collected = tryCollect(entry);
157 entry.setLevel((short)0);
162 support.setLevel(entry, parent.getLevel() + 1);
168 int status = entry.getGCStatus();
169 if((status & CacheEntry.HAS_BEEN_BOUND) == 0) {
171 if(parent != null && !parent.isDiscarded()) {
172 if((parent.getGCStatus() & CacheEntry.HAS_BEEN_BOUND) != 0) {
173 queryProcessor.boundQueries++;
174 entry.setGCStatusFlag(CacheEntry.HAS_BEEN_BOUND, true);
178 if(queryProcessor.hasListenerAfterDisposing(entry)) {
179 if((status & CacheEntry.HAS_BEEN_BOUND) == 0) {
180 queryProcessor.boundQueries++;
181 entry.setGCStatusFlag(CacheEntry.HAS_BEEN_BOUND, true);
193 private boolean tryCollect(CacheEntry entry) {
194 if (!queryProcessor.hasListenerAfterDisposing(entry))
195 if(entry.shouldBeCollected()) {
196 queryProcessor.removeQuery(entry);
207 private void start() {