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