]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl2.java
Merge "Multiple reader thread support for db client"
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / QueryCollectorImpl2.java
1 package org.simantics.db.impl.query;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.IdentityHashMap;
6 import java.util.List;
7 import java.util.Map;
8
9 import org.simantics.databoard.util.IdentityHashSet;
10 import org.simantics.db.common.exception.DebugException;
11 import org.simantics.db.impl.DebugPolicy;
12 import org.simantics.db.impl.query.QueryProcessor.QueryCollectorSupport;
13 import org.simantics.utils.Development;
14
15 class QueryCollectorImpl2 implements QueryProcessor.QueryCollector {
16
17         private final QueryProcessor queryProcessor;
18
19         final private QueryCollectorSupport support;
20
21         private int lastKnownFixedSize = 0;
22
23         QueryCollectorImpl2(QueryProcessor queryProcessor, QueryCollectorSupport support) {
24                 this.queryProcessor = queryProcessor;
25                 this.support = support;
26         }
27
28         private boolean findCollectables(CacheEntry<?> entry, Map<CacheEntry, Boolean> collectables, ArrayList<CacheEntry> result) {
29
30                 if (entry.isDiscarded()) {
31                         if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)
32                                 System.out.println("GC: discarded entry " + entry);
33                         return true;
34                 }
35
36                 if (entry.isPending()) {
37                         if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)
38                                 System.out.println("GC: pending entry " + entry + " was not collected.");
39                         collectables.remove(entry);
40                         return false;
41                 }
42
43                 if (this.queryProcessor.hasListenerAfterDisposing(entry)) {
44                         if (DebugPolicy.COLLECT && DebugPolicy.VERBOSE) {
45                                 System.out.println("GC: listened entry " + entry + " was not collected. Entry=" + entry);
46                         }
47                         collectables.remove(entry);
48                         return false;
49                 }
50
51                 for (CacheEntry parent : entry.getParents(queryProcessor)) {
52
53                         boolean parentIsCollectable = false;
54
55                         if (!collectables.containsKey(parent)) {
56                                 collectables.put(parent, true);
57                                 parentIsCollectable = findCollectables(parent, collectables, result);
58                         } else {
59                                 parentIsCollectable = collectables.get(parent);
60                         }
61
62                         if(!parentIsCollectable) {
63                                 if(DebugPolicy.COLLECT && DebugPolicy.VERBOSE)
64                                         System.out.println("GC: due to bound parent " + parent + " the entry + " + entry + " was not collected.");
65                                 collectables.remove(entry);
66                                 return false;
67                         }
68
69                 }
70
71                 if(entry.shouldBeCollected()) {
72                         // This can be collected
73                         result.add(entry);
74                         return true;
75                 } else {
76                         return false;
77                 }
78
79         }
80
81         private List<CacheEntry> findCollectables() {
82
83                 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
84
85                 IdentityHashMap<CacheEntry, Boolean> collectables = new IdentityHashMap<CacheEntry, Boolean>();
86                 Collection<CacheEntry> rootList = support.getRootList();
87                 for (CacheEntry entry : rootList) {
88                         if(!collectables.containsKey(entry)) {
89                                 collectables.put(entry, true);
90                                 findCollectables(entry, collectables, result);
91                         }
92                 }
93
94                 if(Development.DEVELOPMENT) {
95                         IdentityHashSet<CacheEntry> set = new IdentityHashSet<CacheEntry>();
96                         for(CacheEntry entry : result) {
97                                 if(!set.add(entry)) throw new IllegalStateException();
98                         }
99                 }
100
101                 return result;
102
103         }
104
105         private void doCollect(int currentSize, int maxNumberOfCollectableQueries) {
106
107                 List<CacheEntry> collectables = findCollectables();
108
109                 // Compute amount of free queries
110                 int freeCount = collectables.size();
111
112                 if(DebugPolicy.COLLECT)
113                         System.out.println("collector found " + freeCount + " free queries.");
114
115                 lastKnownFixedSize = currentSize - freeCount;
116
117                 // No need to collect
118                 if(freeCount < maxNumberOfCollectableQueries) return;
119
120                 int target = freeCount - maxNumberOfCollectableQueries/2;
121
122                 if(DebugPolicy.COLLECT)
123                         System.out.println("collector removes " + target + " free queries.");
124
125                 for(CacheEntry entry : collectables) {
126                         if(queryProcessor.removeQuery(entry))
127                                 if(--target < 0) break;
128                 }
129
130                 // Prune discarded parents
131                 ArrayList<CacheEntry> removals = new ArrayList<CacheEntry>();
132                 for (CacheEntry<?> entry : support.allCaches().toCollection()) {
133                         for(CacheEntry p : entry.getParents(queryProcessor)) {
134                                 if(p.isDiscarded()) removals.add(p);
135                         }
136                         for(CacheEntry r : removals) {
137                                 entry.removeParent(r);
138                         }
139                         removals.clear();
140                 }
141
142                 if(DebugPolicy.COLLECT) {
143                         System.out.println("collect found " + freeCount + " collectable entries.");
144                 }
145
146                 return;
147
148         }
149
150         @Override
151         public void collect(int youngTarget, int maxAllowedTimeInMs) {
152
153                 try {
154
155                         int current = support.calculateCurrentSize();
156
157                         if(DebugPolicy.COLLECT)
158                                 new DebugException("checking the need for collecting queries (current=" + current + " , lastKnownFixedSize=" + lastKnownFixedSize + " max free=" + 0 + ")").printStackTrace();
159
160                         queryProcessor.cache.collecting = true;
161
162                         long start = System.nanoTime();
163
164                         doCollect(current, 0);
165
166                         if(DebugPolicy.COLLECT)
167                                 System.out.println("collect finished with " + support.calculateCurrentSize() + " entries (lastKnownFixedSize=" + lastKnownFixedSize + ").");
168
169                         long duration = System.nanoTime() - start;
170
171                         if(DebugPolicy.COLLECT)
172                                 System.err.println("Collect took " + 1e-9*duration + "s.");
173
174                 } catch (Throwable t) {
175                         t.printStackTrace();
176                 }
177
178                 queryProcessor.cache.collecting = false;
179
180         }
181
182
183 }