1 package org.simantics.db.impl.query;
\r
3 import org.simantics.db.impl.query.QueryProcessor.QueryCollectorSupport;
\r
5 class QueryCollectorImpl implements QueryProcessor.QueryCollector {
\r
7 private static final boolean DEBUG = false;
\r
8 private static final boolean DEBUG_STATUS = false;
\r
10 private final QueryProcessor queryProcessor;
\r
12 final private QueryCollectorSupport support;
\r
15 * Set to true: at end of iteration if moreAll is false
\r
16 * Set to false: upon gc start and whenever a prospect is added.
\r
19 boolean doneAll = false;
\r
21 * Set to true: upon gc start and whenever a prospect is added.
\r
22 * Set to false: at end of entry iteration
\r
23 * => if this is already false at end of entry iteration => no more work to be done
\r
28 * Change propagation is in progress
\r
30 boolean propagate = true;
\r
33 private static final int COLLECT_N = 1000;
\r
35 private long spent = 0;
\r
37 QueryCollectorImpl(QueryProcessor queryProcessor, QueryCollectorSupport support) {
\r
38 this.queryProcessor = queryProcessor;
\r
39 this.support = support;
\r
43 public void collect(int youngTarget, int allowedTimeInMs) {
\r
45 long start = System.nanoTime();
\r
47 // Refresh current size
\r
48 int size = support.calculateCurrentSize();
\r
49 int bound = queryProcessor.boundQueries;
\r
50 int young = size - bound;
\r
51 int youngPct = size > 0 ? 100*young / size : 0;
\r
53 // Initialize support for new run
\r
54 // If support returns 0 we are starting from 0
\r
55 if(support.start(youngTarget == 0)) {
\r
59 // We monitor all prospects here
\r
60 CacheEntryBase prospect = support.iterate(0);
\r
61 while(prospect != null) {
\r
62 if(prospect.isDiscarded()) {
\r
66 CacheEntry parent = prospect.getFirstParent(queryProcessor);
\r
67 if(parent == null) {
\r
68 tryCollect(prospect);
\r
70 support.setLevel(prospect, parent.getLevel() + 1);
\r
73 prospect = support.iterate(0);
\r
76 // If no prospects were collected and most of the queries are old we can stop here
\r
77 if(!propagate && youngPct < youngTarget) {
\r
78 // System.err.println("collect2 skipped");
\r
79 // System.err.println("-size=" + size);
\r
80 // System.err.println("-young=" + young);
\r
86 long test = (long)allowedTimeInMs*1000000;
\r
92 size = support.getCurrentSize();
\r
93 bound = queryProcessor.boundQueries;
\r
95 long elapsed = System.nanoTime()-start;
\r
96 boolean timeCondition = elapsed > test;
\r
98 if(doneAll || timeCondition) {
\r
103 System.err.println("Query collector used " + 1e-9*elapsed + "s total queries: " + size + " bound queries: " + bound + " spent: " + (double)spent*1e-9);
\r
109 // Iterate all entries and update sets
\r
111 // long start2 = System.nanoTime();
\r
112 for(int i=0;i<COLLECT_N;i++) {
\r
113 CacheEntryBase entry = support.iterate(Integer.MAX_VALUE);
\r
114 if(entry == null) {
\r
116 System.err.println("finished iteration");
\r
117 System.err.println("-moreAll=" + moreAll);
\r
119 if(moreAll < 1000) {
\r
127 CacheEntry parent = entry.getFirstParent(queryProcessor);
\r
128 if(parent == null) {
\r
130 boolean collected = tryCollect(entry);
\r
132 entry.setLevel((short)0);
\r
137 parent = entry.pruneFirstParents();
\r
138 if(parent == null) {
\r
140 boolean collected = tryCollect(entry);
\r
142 entry.setLevel((short)0);
\r
147 support.setLevel(entry, parent.getLevel() + 1);
\r
153 int status = entry.getGCStatus();
\r
154 if((status & CacheEntry.HAS_BEEN_BOUND) == 0) {
\r
156 if(parent != null && !parent.isDiscarded()) {
\r
157 if((parent.getGCStatus() & CacheEntry.HAS_BEEN_BOUND) != 0) {
\r
158 queryProcessor.boundQueries++;
\r
159 entry.setGCStatusFlag(CacheEntry.HAS_BEEN_BOUND, true);
\r
163 if(queryProcessor.hasListenerAfterDisposing(entry)) {
\r
164 if((status & CacheEntry.HAS_BEEN_BOUND) == 0) {
\r
165 queryProcessor.boundQueries++;
\r
166 entry.setGCStatusFlag(CacheEntry.HAS_BEEN_BOUND, true);
\r
178 private boolean tryCollect(CacheEntry entry) {
\r
179 if (!queryProcessor.hasListenerAfterDisposing(entry))
\r
180 if(entry.shouldBeCollected()) {
\r
181 queryProcessor.removeQuery(entry);
\r
191 private void start() {
\r