]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java
Trying to remove synchronization problems
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / QueryCache.java
1 package org.simantics.db.impl.query;
2
3 import org.simantics.db.ObjectResourceIdMap;
4 import org.simantics.db.RelationInfo;
5 import org.simantics.db.common.utils.Logger;
6 import org.simantics.db.exception.DatabaseException;
7 import org.simantics.db.impl.graph.ReadGraphImpl;
8 import org.simantics.db.impl.procedure.InternalProcedure;
9 import org.simantics.db.impl.query.QueryProcessor.SessionTask;
10 import org.simantics.db.procedure.AsyncMultiProcedure;
11 import org.simantics.db.procedure.AsyncProcedure;
12 import org.simantics.db.procedure.ListenerBase;
13 import org.simantics.db.request.AsyncMultiRead;
14 import org.simantics.db.request.AsyncRead;
15 import org.simantics.db.request.ExternalRead;
16 import org.simantics.db.request.MultiRead;
17 import org.simantics.db.request.Read;
18
19 public class QueryCache extends QueryCacheBase {
20
21     public QueryCache(QuerySupport querySupport, int threads) {
22         super(querySupport, threads);
23     }
24
25     Objects getOrCreateObjects(QueryProcessor processor, int r1, int r2) throws DatabaseException {
26         Objects existing = null;
27         synchronized(objectsMap) {
28             existing = (Objects)objectsMap.get(r1,r2);
29             if(existing == null) {
30                 existing = new Objects(r1,r2);
31                 existing.clearResult(querySupport);
32                 existing.setPending();
33                 objectsMap.put(keyR2(r1,r2), existing);
34                 size++;
35                 return existing;
36             }
37             if(existing.requiresComputation()) {
38                 existing.setPending();
39                 return existing;
40             }
41         }
42         if(existing.isPending()) waitPending(processor, existing);
43         return existing;
44     }
45     
46     void remove(Objects entry) {
47         synchronized(objectsMap) {
48             objectsMap.remove(entry.id);
49         }
50     }
51     
52     public static void runnerObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
53         QueryCache cache  = graph.processor.cache;
54         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) {
55             Objects.computeForEach(graph, r1,r2, null, procedure);
56             return;
57         }
58         Objects entry = (Objects)cache.getOrCreateObjects(graph.processor, r1,r2);
59         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureObjects;
60         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
61         if(entry.isReady()) entry.performFromCache(graph, procedure_);
62         else {
63           assert(entry.isPending());
64             Objects.computeForEach(graph, r1,r2, entry, procedure_);
65             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
66         }
67     }
68     
69     Statements getOrCreateStatements(QueryProcessor processor, int r1, int r2) throws DatabaseException {
70         Statements existing = null;
71         synchronized(statementsMap) {
72             existing = (Statements)statementsMap.get(r1,r2);
73             if(existing == null) {
74                 existing = new Statements(r1,r2);
75                 existing.clearResult(querySupport);
76                 existing.setPending();
77                 statementsMap.put(keyR2(r1,r2), existing);
78                 size++;
79                 return existing;
80             }
81             if(existing.requiresComputation()) {
82                 existing.setPending();
83                 return existing;
84             }
85         }
86         if(existing.isPending()) waitPending(processor, existing);
87         return existing;
88     }
89     
90     void remove(Statements entry) {
91         synchronized(statementsMap) {
92             statementsMap.remove(entry.id);
93         }
94     }
95     
96     public static void runnerStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final TripleIntProcedure procedure) throws DatabaseException {
97         QueryCache cache  = graph.processor.cache;
98         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) {
99             Statements.computeForEach(graph, r1,r2, null, procedure);
100             return;
101         }
102         Statements entry = (Statements)cache.getOrCreateStatements(graph.processor, r1,r2);
103         TripleIntProcedure procedure_ = procedure != null ? procedure : emptyProcedureStatements;
104         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
105         if(entry.isReady()) entry.performFromCache(graph, procedure_);
106         else {
107           assert(entry.isPending());
108             Statements.computeForEach(graph, r1,r2, entry, procedure_);
109             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
110         }
111     }
112     
113     DirectObjects getOrCreateDirectObjects(QueryProcessor processor, int r1, int r2) throws DatabaseException {
114         DirectObjects existing = null;
115         synchronized(directObjectsMap) {
116             existing = (DirectObjects)directObjectsMap.get(r1,r2);
117             if(existing == null) {
118                 existing = new DirectObjects(r1,r2);
119                 existing.clearResult(querySupport);
120                 existing.setPending();
121                 directObjectsMap.put(keyR2(r1,r2), existing);
122                 size++;
123                 return existing;
124             }
125             if(existing.requiresComputation()) {
126                 existing.setPending();
127                 return existing;
128             }
129         }
130         if(existing.isPending()) waitPending(processor, existing);
131         return existing;
132     }
133     
134     void remove(DirectObjects entry) {
135         synchronized(directObjectsMap) {
136             directObjectsMap.remove(entry.id);
137         }
138     }
139     
140     public static void runnerDirectObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
141         QueryCache cache  = graph.processor.cache;
142         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) {
143             DirectObjects.computeForEach(graph, r1,r2, null, procedure);
144             return;
145         }
146         DirectObjects entry = (DirectObjects)cache.getOrCreateDirectObjects(graph.processor, r1,r2);
147         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureDirectObjects;
148         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
149         if(entry.isReady()) entry.performFromCache(graph, procedure_);
150         else {
151           assert(entry.isPending());
152             DirectObjects.computeForEach(graph, r1,r2, entry, procedure_);
153             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
154         }
155     }
156     
157     RelationInfoQuery getOrCreateRelationInfoQuery(QueryProcessor processor, int r) throws DatabaseException {
158         RelationInfoQuery existing = null;
159         synchronized(relationInfoQueryMap) {
160             existing = (RelationInfoQuery)relationInfoQueryMap.get(r);
161             if(existing == null) {
162                 existing = new RelationInfoQuery(r);
163                 existing.clearResult(querySupport);
164                 existing.setPending();
165                 relationInfoQueryMap.put(keyR(r), existing);
166                 size++;
167                 return existing;
168             }
169             if(existing.requiresComputation()) {
170                 existing.setPending();
171                 return existing;
172             }
173         }
174         if(existing.isPending()) waitPending(processor, existing);
175         return existing;
176     }
177     
178     void remove(RelationInfoQuery entry) {
179         synchronized(relationInfoQueryMap) {
180             relationInfoQueryMap.remove(entry.id);
181         }
182     }
183     
184     public static void runnerRelationInfoQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<RelationInfo> procedure) throws DatabaseException {
185         QueryCache cache  = graph.processor.cache;
186         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
187             RelationInfoQuery.computeForEach(graph, r, null, procedure);
188             return;
189         }
190         RelationInfoQuery entry = (RelationInfoQuery)cache.getOrCreateRelationInfoQuery(graph.processor, r);
191         InternalProcedure<RelationInfo> procedure_ = procedure != null ? procedure : emptyProcedureRelationInfoQuery;
192         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
193         if(entry.isReady()) entry.performFromCache(graph, procedure_);
194         else {
195           assert(entry.isPending());
196             RelationInfoQuery.computeForEach(graph, r, entry, procedure_);
197             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
198         }
199     }
200     
201     URIToResource getOrCreateURIToResource(QueryProcessor processor, String id) throws DatabaseException {
202         URIToResource existing = null;
203         synchronized(uRIToResourceMap) {
204             existing = (URIToResource)uRIToResourceMap.get(id);
205             if(existing == null) {
206                 existing = new URIToResource(id);
207                 existing.clearResult(querySupport);
208                 existing.setPending();
209                 uRIToResourceMap.put(keyID(id), existing);
210                 size++;
211                 return existing;
212             }
213             if(existing.requiresComputation()) {
214                 existing.setPending();
215                 return existing;
216             }
217         }
218         if(existing.isPending()) waitPending(processor, existing);
219         return existing;
220     }
221     
222     void remove(URIToResource entry) {
223         synchronized(uRIToResourceMap) {
224             uRIToResourceMap.remove(entry.id);
225         }
226     }
227     
228     public static void runnerURIToResource(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener, final InternalProcedure<Integer> procedure) throws DatabaseException {
229         QueryCache cache  = graph.processor.cache;
230         if(parent == null && listener == null && !cache.shouldCache(graph.processor, id)) {
231             URIToResource.computeForEach(graph, id, null, procedure);
232             return;
233         }
234         URIToResource entry = (URIToResource)cache.getOrCreateURIToResource(graph.processor, id);
235         InternalProcedure<Integer> procedure_ = procedure != null ? procedure : emptyProcedureURIToResource;
236         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
237         if(entry.isReady()) entry.performFromCache(graph, procedure_);
238         else {
239           assert(entry.isPending());
240             URIToResource.computeForEach(graph, id, entry, procedure_);
241             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
242         }
243     }
244     
245     ValueQuery getOrCreateValueQuery(QueryProcessor processor, int r) throws DatabaseException {
246         ValueQuery existing = null;
247         synchronized(valueQueryMap) {
248             existing = (ValueQuery)valueQueryMap.get(r);
249             if(existing == null) {
250                 existing = new ValueQuery(r);
251                 existing.clearResult(querySupport);
252                 existing.setPending();
253                 valueQueryMap.put(keyR(r), existing);
254                 size++;
255                 return existing;
256             }
257             if(existing.requiresComputation()) {
258                 existing.setPending();
259                 return existing;
260             }
261         }
262         if(existing.isPending()) waitPending(processor, existing);
263         return existing;
264     }
265     
266     void remove(ValueQuery entry) {
267         synchronized(valueQueryMap) {
268             valueQueryMap.remove(entry.id);
269         }
270     }
271     
272     public static void runnerValueQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<byte[]> procedure) throws DatabaseException {
273         QueryCache cache  = graph.processor.cache;
274         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
275             ValueQuery.computeForEach(graph, r, null, procedure);
276             return;
277         }
278         ValueQuery entry = (ValueQuery)cache.getOrCreateValueQuery(graph.processor, r);
279         InternalProcedure<byte[]> procedure_ = procedure != null ? procedure : emptyProcedureValueQuery;
280         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
281         if(entry.isReady()) entry.performFromCache(graph, procedure_);
282         else {
283           assert(entry.isPending());
284             ValueQuery.computeForEach(graph, r, entry, procedure_);
285             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
286         }
287     }
288     
289     OrderedSet getOrCreateOrderedSet(QueryProcessor processor, int r) throws DatabaseException {
290         OrderedSet existing = null;
291         synchronized(orderedSetMap) {
292             existing = (OrderedSet)orderedSetMap.get(r);
293             if(existing == null) {
294                 existing = new OrderedSet(r);
295                 existing.clearResult(querySupport);
296                 existing.setPending();
297                 orderedSetMap.put(keyR(r), existing);
298                 size++;
299                 return existing;
300             }
301             if(existing.requiresComputation()) {
302                 existing.setPending();
303                 return existing;
304             }
305         }
306         if(existing.isPending()) waitPending(processor, existing);
307         return existing;
308     }
309     
310     void remove(OrderedSet entry) {
311         synchronized(orderedSetMap) {
312             orderedSetMap.remove(entry.id);
313         }
314     }
315     
316     public static void runnerOrderedSet(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
317         QueryCache cache  = graph.processor.cache;
318         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
319             OrderedSet.computeForEach(graph, r, null, procedure);
320             return;
321         }
322         OrderedSet entry = (OrderedSet)cache.getOrCreateOrderedSet(graph.processor, r);
323         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureOrderedSet;
324         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
325         if(entry.isReady()) entry.performFromCache(graph, procedure_);
326         else {
327           assert(entry.isPending());
328             OrderedSet.computeForEach(graph, r, entry, procedure_);
329             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
330         }
331     }
332     
333     PrincipalTypes getOrCreatePrincipalTypes(QueryProcessor processor, int r) throws DatabaseException {
334         PrincipalTypes existing = null;
335         synchronized(principalTypesMap) {
336             existing = (PrincipalTypes)principalTypesMap.get(r);
337             if(existing == null) {
338                 existing = new PrincipalTypes(r);
339                 existing.clearResult(querySupport);
340                 existing.setPending();
341                 principalTypesMap.put(keyR(r), existing);
342                 size++;
343                 return existing;
344             }
345             if(existing.requiresComputation()) {
346                 existing.setPending();
347                 return existing;
348             }
349         }
350         if(existing.isPending()) waitPending(processor, existing);
351         return existing;
352     }
353     
354     void remove(PrincipalTypes entry) {
355         synchronized(principalTypesMap) {
356             principalTypesMap.remove(entry.id);
357         }
358     }
359     
360     public static void runnerPrincipalTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
361         QueryCache cache  = graph.processor.cache;
362         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
363             PrincipalTypes.computeForEach(graph, r, null, procedure);
364             return;
365         }
366         PrincipalTypes entry = (PrincipalTypes)cache.getOrCreatePrincipalTypes(graph.processor, r);
367         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedurePrincipalTypes;
368         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
369         if(entry.isReady()) entry.performFromCache(graph, procedure_);
370         else {
371           assert(entry.isPending());
372             PrincipalTypes.computeForEach(graph, r, entry, procedure_);
373             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
374         }
375     }
376     
377     DirectPredicates getOrCreateDirectPredicates(QueryProcessor processor, int r) throws DatabaseException {
378         DirectPredicates existing = null;
379         synchronized(directPredicatesMap) {
380             existing = (DirectPredicates)directPredicatesMap.get(r);
381             if(existing == null) {
382                 existing = new DirectPredicates(r);
383                 existing.clearResult(querySupport);
384                 existing.setPending();
385                 directPredicatesMap.put(keyR(r), existing);
386                 size++;
387                 return existing;
388             }
389             if(existing.requiresComputation()) {
390                 existing.setPending();
391                 return existing;
392             }
393         }
394         if(existing.isPending()) waitPending(processor, existing);
395         return existing;
396     }
397     
398     void remove(DirectPredicates entry) {
399         synchronized(directPredicatesMap) {
400             directPredicatesMap.remove(entry.id);
401         }
402     }
403     
404     public static void runnerDirectPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
405         QueryCache cache  = graph.processor.cache;
406         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
407             DirectPredicates.computeForEach(graph, r, null, procedure);
408             return;
409         }
410         DirectPredicates entry = (DirectPredicates)cache.getOrCreateDirectPredicates(graph.processor, r);
411         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureDirectPredicates;
412         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
413         if(entry.isReady()) entry.performFromCache(graph, procedure_);
414         else {
415           assert(entry.isPending());
416             DirectPredicates.computeForEach(graph, r, entry, procedure_);
417             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
418         }
419     }
420     
421     Predicates getOrCreatePredicates(QueryProcessor processor, int r) throws DatabaseException {
422         Predicates existing = null;
423         synchronized(predicatesMap) {
424             existing = (Predicates)predicatesMap.get(r);
425             if(existing == null) {
426                 existing = new Predicates(r);
427                 existing.clearResult(querySupport);
428                 existing.setPending();
429                 predicatesMap.put(keyR(r), existing);
430                 size++;
431                 return existing;
432             }
433             if(existing.requiresComputation()) {
434                 existing.setPending();
435                 return existing;
436             }
437         }
438         if(existing.isPending()) waitPending(processor, existing);
439         return existing;
440     }
441     
442     void remove(Predicates entry) {
443         synchronized(predicatesMap) {
444             predicatesMap.remove(entry.id);
445         }
446     }
447     
448     public static void runnerPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
449         QueryCache cache  = graph.processor.cache;
450         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
451             Predicates.computeForEach(graph, r, null, procedure);
452             return;
453         }
454         Predicates entry = (Predicates)cache.getOrCreatePredicates(graph.processor, r);
455         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedurePredicates;
456         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
457         if(entry.isReady()) entry.performFromCache(graph, procedure_);
458         else {
459           assert(entry.isPending());
460             Predicates.computeForEach(graph, r, entry, procedure_);
461             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
462         }
463     }
464     
465     ReadEntry getOrCreateReadEntry(QueryProcessor processor, Read<?> r, boolean isSync) throws DatabaseException {
466         ReadEntry existing = null;
467         synchronized(readEntryMap) {
468             existing = (ReadEntry)readEntryMap.get(r);
469             if(existing == null) {
470                 existing = new ReadEntry(r);
471                 existing.clearResult(querySupport);
472                 existing.setPending();
473                 readEntryMap.put(id(r), existing);
474                 size++;
475                 return existing;
476             }
477             if(existing.requiresComputation()) {
478                 existing.setPending();
479                 return existing;
480             }
481         }
482         if(existing.isPending()) {
483           if(isSync) waitPending(processor, existing);
484           else return null;
485         }
486         return existing;
487     }
488     
489     void remove(ReadEntry entry) {
490         synchronized(readEntryMap) {
491             readEntryMap.remove(entry.request);
492         }
493     }
494     
495     public static void runnerReadEntry(ReadGraphImpl graph, Read<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure, boolean isSync) throws DatabaseException {
496         QueryCache cache  = graph.processor.cache;
497         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
498             ReadEntry.computeForEach(graph, r, null, procedure);
499             return;
500         }
501         ReadEntry entry = (ReadEntry)cache.getOrCreateReadEntry(graph.processor, r, isSync);
502         if(entry == null) {
503             graph.processor.schedule(new SessionTask(false) {
504                 @Override
505                 public void run(int thread) {
506                     try {
507                         assert(!isSync);
508                         runnerReadEntry(graph, r, parent, listener, procedure, isSync);
509                     } catch (DatabaseException e) {
510                         Logger.defaultLogError(e);
511                     }
512                 }
513             });
514             return;
515         }
516         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureReadEntry;
517         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
518         if(entry.isReady()) entry.performFromCache(graph, procedure_);
519         else {
520           assert(entry.isPending());
521             ReadEntry.computeForEach(graph, r, entry, procedure_);
522             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
523         }
524     }
525     
526     AsyncReadEntry getOrCreateAsyncReadEntry(QueryProcessor processor, AsyncRead<?> r, boolean isSync) throws DatabaseException {
527         AsyncReadEntry existing = null;
528         synchronized(asyncReadEntryMap) {
529             existing = (AsyncReadEntry)asyncReadEntryMap.get(r);
530             if(existing == null) {
531                 existing = new AsyncReadEntry(r);
532                 existing.clearResult(querySupport);
533                 existing.setPending();
534                 asyncReadEntryMap.put(id(r), existing);
535                 size++;
536                 return existing;
537             }
538             if(existing.requiresComputation()) {
539                 existing.setPending();
540                 return existing;
541             }
542         }
543         if(existing.isPending()) {
544           if(isSync) waitPending(processor, existing);
545           else return null;
546         }
547         return existing;
548     }
549     
550     void remove(AsyncReadEntry entry) {
551         synchronized(asyncReadEntryMap) {
552             asyncReadEntryMap.remove(entry.request);
553         }
554     }
555     
556     public static void runnerAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure, boolean isSync) throws DatabaseException {
557         QueryCache cache  = graph.processor.cache;
558         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
559             AsyncReadEntry.computeForEach(graph, r, null, procedure);
560             return;
561         }
562         AsyncReadEntry entry = (AsyncReadEntry)cache.getOrCreateAsyncReadEntry(graph.processor, r, isSync);
563         if(entry == null) {
564             graph.processor.schedule(new SessionTask(false) {
565                 @Override
566                 public void run(int thread) {
567                     try {
568                         assert(!isSync);
569                         runnerAsyncReadEntry(graph, r, parent, listener, procedure, isSync);
570                     } catch (DatabaseException e) {
571                         Logger.defaultLogError(e);
572                     }
573                 }
574             });
575             return;
576         }
577         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureAsyncReadEntry;
578         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
579         if(entry.isReady()) entry.performFromCache(graph, procedure_);
580         else {
581           assert(entry.isPending());
582             AsyncReadEntry.computeForEach(graph, r, entry, procedure_);
583             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
584         }
585     }
586     
587     Types getOrCreateTypes(QueryProcessor processor, int r) throws DatabaseException {
588         Types existing = null;
589         synchronized(typesMap) {
590             existing = (Types)typesMap.get(r);
591             if(existing == null) {
592                 existing = new Types(r);
593                 existing.clearResult(querySupport);
594                 existing.setPending();
595                 typesMap.put(keyR(r), existing);
596                 size++;
597                 return existing;
598             }
599             if(existing.requiresComputation()) {
600                 existing.setPending();
601                 return existing;
602             }
603         }
604         if(existing.isPending()) waitPending(processor, existing);
605         return existing;
606     }
607     
608     void remove(Types entry) {
609         synchronized(typesMap) {
610             typesMap.remove(entry.id);
611         }
612     }
613     
614     public static void runnerTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
615         QueryCache cache  = graph.processor.cache;
616         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
617             Types.computeForEach(graph, r, null, procedure);
618             return;
619         }
620         Types entry = (Types)cache.getOrCreateTypes(graph.processor, r);
621         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureTypes;
622         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
623         if(entry.isReady()) entry.performFromCache(graph, procedure_);
624         else {
625           assert(entry.isPending());
626             Types.computeForEach(graph, r, entry, procedure_);
627             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
628         }
629     }
630     
631     ChildMap getOrCreateChildMap(QueryProcessor processor, int r) throws DatabaseException {
632         ChildMap existing = null;
633         synchronized(childMapMap) {
634             existing = (ChildMap)childMapMap.get(r);
635             if(existing == null) {
636                 existing = new ChildMap(r);
637                 existing.clearResult(querySupport);
638                 existing.setPending();
639                 childMapMap.put(keyR(r), existing);
640                 size++;
641                 return existing;
642             }
643             if(existing.requiresComputation()) {
644                 existing.setPending();
645                 return existing;
646             }
647         }
648         if(existing.isPending()) waitPending(processor, existing);
649         return existing;
650     }
651     
652     void remove(ChildMap entry) {
653         synchronized(childMapMap) {
654             childMapMap.remove(entry.id);
655         }
656     }
657     
658     public static void runnerChildMap(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<ObjectResourceIdMap<String>> procedure) throws DatabaseException {
659         QueryCache cache  = graph.processor.cache;
660         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
661             ChildMap.computeForEach(graph, r, null, procedure);
662             return;
663         }
664         ChildMap entry = (ChildMap)cache.getOrCreateChildMap(graph.processor, r);
665         InternalProcedure<ObjectResourceIdMap<String>> procedure_ = procedure != null ? procedure : emptyProcedureChildMap;
666         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
667         if(entry.isReady()) entry.performFromCache(graph, procedure_);
668         else {
669           assert(entry.isPending());
670             ChildMap.computeForEach(graph, r, entry, procedure_);
671             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
672         }
673     }
674     
675     TypeHierarchy getOrCreateTypeHierarchy(QueryProcessor processor, int r) throws DatabaseException {
676         TypeHierarchy existing = null;
677         synchronized(typeHierarchyMap) {
678             existing = (TypeHierarchy)typeHierarchyMap.get(r);
679             if(existing == null) {
680                 existing = new TypeHierarchy(r);
681                 existing.clearResult(querySupport);
682                 existing.setPending();
683                 typeHierarchyMap.put(keyR(r), existing);
684                 size++;
685                 return existing;
686             }
687             if(existing.requiresComputation()) {
688                 existing.setPending();
689                 return existing;
690             }
691         }
692         if(existing.isPending()) waitPending(processor, existing);
693         return existing;
694     }
695     
696     void remove(TypeHierarchy entry) {
697         synchronized(typeHierarchyMap) {
698             typeHierarchyMap.remove(entry.id);
699         }
700     }
701     
702     public static void runnerTypeHierarchy(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
703         QueryCache cache  = graph.processor.cache;
704         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
705             TypeHierarchy.computeForEach(graph, r, null, procedure);
706             return;
707         }
708         TypeHierarchy entry = (TypeHierarchy)cache.getOrCreateTypeHierarchy(graph.processor, r);
709         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureTypeHierarchy;
710         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
711         if(entry.isReady()) entry.performFromCache(graph, procedure_);
712         else {
713           assert(entry.isPending());
714             TypeHierarchy.computeForEach(graph, r, entry, procedure_);
715             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
716         }
717     }
718     
719     SuperTypes getOrCreateSuperTypes(QueryProcessor processor, int r) throws DatabaseException {
720         SuperTypes existing = null;
721         synchronized(superTypesMap) {
722             existing = (SuperTypes)superTypesMap.get(r);
723             if(existing == null) {
724                 existing = new SuperTypes(r);
725                 existing.clearResult(querySupport);
726                 existing.setPending();
727                 superTypesMap.put(keyR(r), existing);
728                 size++;
729                 return existing;
730             }
731             if(existing.requiresComputation()) {
732                 existing.setPending();
733                 return existing;
734             }
735         }
736         if(existing.isPending()) waitPending(processor, existing);
737         return existing;
738     }
739     
740     void remove(SuperTypes entry) {
741         synchronized(superTypesMap) {
742             superTypesMap.remove(entry.id);
743         }
744     }
745     
746     public static void runnerSuperTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
747         QueryCache cache  = graph.processor.cache;
748         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
749             SuperTypes.computeForEach(graph, r, null, procedure);
750             return;
751         }
752         SuperTypes entry = (SuperTypes)cache.getOrCreateSuperTypes(graph.processor, r);
753         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureSuperTypes;
754         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
755         if(entry.isReady()) entry.performFromCache(graph, procedure_);
756         else {
757           assert(entry.isPending());
758             SuperTypes.computeForEach(graph, r, entry, procedure_);
759             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
760         }
761     }
762     
763     SuperRelations getOrCreateSuperRelations(QueryProcessor processor, int r) throws DatabaseException {
764         SuperRelations existing = null;
765         synchronized(superRelationsMap) {
766             existing = (SuperRelations)superRelationsMap.get(r);
767             if(existing == null) {
768                 existing = new SuperRelations(r);
769                 existing.clearResult(querySupport);
770                 existing.setPending();
771                 superRelationsMap.put(keyR(r), existing);
772                 size++;
773                 return existing;
774             }
775             if(existing.requiresComputation()) {
776                 existing.setPending();
777                 return existing;
778             }
779         }
780         if(existing.isPending()) waitPending(processor, existing);
781         return existing;
782     }
783     
784     void remove(SuperRelations entry) {
785         synchronized(superRelationsMap) {
786             superRelationsMap.remove(entry.id);
787         }
788     }
789     
790     public static void runnerSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
791         QueryCache cache  = graph.processor.cache;
792         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
793             SuperRelations.computeForEach(graph, r, null, procedure);
794             return;
795         }
796         SuperRelations entry = (SuperRelations)cache.getOrCreateSuperRelations(graph.processor, r);
797         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureSuperRelations;
798         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
799         if(entry.isReady()) entry.performFromCache(graph, procedure_);
800         else {
801           assert(entry.isPending());
802             SuperRelations.computeForEach(graph, r, entry, procedure_);
803             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
804         }
805     }
806     
807     AssertedPredicates getOrCreateAssertedPredicates(QueryProcessor processor, int r) throws DatabaseException {
808         AssertedPredicates existing = null;
809         synchronized(assertedPredicatesMap) {
810             existing = (AssertedPredicates)assertedPredicatesMap.get(r);
811             if(existing == null) {
812                 existing = new AssertedPredicates(r);
813                 existing.clearResult(querySupport);
814                 existing.setPending();
815                 assertedPredicatesMap.put(keyR(r), existing);
816                 size++;
817                 return existing;
818             }
819             if(existing.requiresComputation()) {
820                 existing.setPending();
821                 return existing;
822             }
823         }
824         if(existing.isPending()) waitPending(processor, existing);
825         return existing;
826     }
827     
828     void remove(AssertedPredicates entry) {
829         synchronized(assertedPredicatesMap) {
830             assertedPredicatesMap.remove(entry.id);
831         }
832     }
833     
834     public static void runnerAssertedPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
835         QueryCache cache  = graph.processor.cache;
836         AssertedPredicates entry = (AssertedPredicates)cache.getOrCreateAssertedPredicates(graph.processor, r);
837         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureAssertedPredicates;
838         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
839         if(entry.isReady()) entry.performFromCache(graph, procedure_);
840         else {
841           assert(entry.isPending());
842             entry.compute(graph, procedure_);
843             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
844         }
845     }
846     
847     AssertedStatements getOrCreateAssertedStatements(QueryProcessor processor, int r1, int r2) throws DatabaseException {
848         AssertedStatements existing = null;
849         synchronized(assertedStatementsMap) {
850             existing = (AssertedStatements)assertedStatementsMap.get(r1,r2);
851             if(existing == null) {
852                 existing = new AssertedStatements(r1,r2);
853                 existing.clearResult(querySupport);
854                 existing.setPending();
855                 assertedStatementsMap.put(keyR2(r1,r2), existing);
856                 size++;
857                 return existing;
858             }
859             if(existing.requiresComputation()) {
860                 existing.setPending();
861                 return existing;
862             }
863         }
864         if(existing.isPending()) waitPending(processor, existing);
865         return existing;
866     }
867     
868     void remove(AssertedStatements entry) {
869         synchronized(assertedStatementsMap) {
870             assertedStatementsMap.remove(entry.id);
871         }
872     }
873     
874     public static void runnerAssertedStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final TripleIntProcedure procedure) throws DatabaseException {
875         QueryCache cache  = graph.processor.cache;
876         AssertedStatements entry = (AssertedStatements)cache.getOrCreateAssertedStatements(graph.processor, r1,r2);
877         TripleIntProcedure procedure_ = procedure != null ? procedure : emptyProcedureAssertedStatements;
878         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
879         if(entry.isReady()) entry.performFromCache(graph, procedure_);
880         else {
881           assert(entry.isPending());
882             entry.compute(graph, procedure_);
883             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
884         }
885     }
886     
887     DirectSuperRelations getOrCreateDirectSuperRelations(QueryProcessor processor, int r) throws DatabaseException {
888         DirectSuperRelations existing = null;
889         synchronized(directSuperRelationsMap) {
890             existing = (DirectSuperRelations)directSuperRelationsMap.get(r);
891             if(existing == null) {
892                 existing = new DirectSuperRelations(r);
893                 existing.clearResult(querySupport);
894                 existing.setPending();
895                 directSuperRelationsMap.put(keyR(r), existing);
896                 size++;
897                 return existing;
898             }
899             if(existing.requiresComputation()) {
900                 existing.setPending();
901                 return existing;
902             }
903         }
904         if(existing.isPending()) waitPending(processor, existing);
905         return existing;
906     }
907     
908     void remove(DirectSuperRelations entry) {
909         synchronized(directSuperRelationsMap) {
910             directSuperRelationsMap.remove(entry.id);
911         }
912     }
913     
914     public static void runnerDirectSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
915         QueryCache cache  = graph.processor.cache;
916         DirectSuperRelations entry = (DirectSuperRelations)cache.getOrCreateDirectSuperRelations(graph.processor, r);
917         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureDirectSuperRelations;
918         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
919         if(entry.isReady()) entry.performFromCache(graph, procedure_);
920         else {
921           assert(entry.isPending());
922             entry.compute(graph, procedure_);
923             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
924         }
925     }
926     
927     MultiReadEntry getOrCreateMultiReadEntry(QueryProcessor processor, MultiRead<?> r) throws DatabaseException {
928         MultiReadEntry existing = null;
929         synchronized(multiReadEntryMap) {
930             existing = (MultiReadEntry)multiReadEntryMap.get(r);
931             if(existing == null) {
932                 existing = new MultiReadEntry(r);
933                 existing.clearResult(querySupport);
934                 existing.setPending();
935                 multiReadEntryMap.put(id(r), existing);
936                 size++;
937                 return existing;
938             }
939             if(existing.requiresComputation()) {
940                 existing.setPending();
941                 return existing;
942             }
943         }
944         if(existing.isPending()) waitPending(processor, existing);
945         return existing;
946     }
947     
948     void remove(MultiReadEntry entry) {
949         synchronized(multiReadEntryMap) {
950             multiReadEntryMap.remove(entry.request);
951         }
952     }
953     
954     public static void runnerMultiReadEntry(ReadGraphImpl graph, MultiRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncMultiProcedure procedure) throws DatabaseException {
955         QueryCache cache  = graph.processor.cache;
956         MultiReadEntry entry = (MultiReadEntry)cache.getOrCreateMultiReadEntry(graph.processor, r);
957         AsyncMultiProcedure procedure_ = procedure != null ? procedure : emptyProcedureMultiReadEntry;
958         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
959         if(entry.isReady()) entry.performFromCache(graph, procedure_);
960         else {
961           assert(entry.isPending());
962             entry.compute(graph, procedure_);
963             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
964         }
965     }
966     
967     AsyncMultiReadEntry getOrCreateAsyncMultiReadEntry(QueryProcessor processor, AsyncMultiRead<?> r) throws DatabaseException {
968         AsyncMultiReadEntry existing = null;
969         synchronized(asyncMultiReadEntryMap) {
970             existing = (AsyncMultiReadEntry)asyncMultiReadEntryMap.get(r);
971             if(existing == null) {
972                 existing = new AsyncMultiReadEntry(r);
973                 existing.clearResult(querySupport);
974                 existing.setPending();
975                 asyncMultiReadEntryMap.put(id(r), existing);
976                 size++;
977                 return existing;
978             }
979             if(existing.requiresComputation()) {
980                 existing.setPending();
981                 return existing;
982             }
983         }
984         if(existing.isPending()) waitPending(processor, existing);
985         return existing;
986     }
987     
988     void remove(AsyncMultiReadEntry entry) {
989         synchronized(asyncMultiReadEntryMap) {
990             asyncMultiReadEntryMap.remove(entry.request);
991         }
992     }
993     
994     public static void runnerAsyncMultiReadEntry(ReadGraphImpl graph, AsyncMultiRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncMultiProcedure procedure) throws DatabaseException {
995         QueryCache cache  = graph.processor.cache;
996         AsyncMultiReadEntry entry = (AsyncMultiReadEntry)cache.getOrCreateAsyncMultiReadEntry(graph.processor, r);
997         AsyncMultiProcedure procedure_ = procedure != null ? procedure : emptyProcedureAsyncMultiReadEntry;
998         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
999         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1000         else {
1001           assert(entry.isPending());
1002             entry.compute(graph, procedure_);
1003             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1004         }
1005     }
1006     
1007     ExternalReadEntry getOrCreateExternalReadEntry(QueryProcessor processor, ExternalRead<?> r) throws DatabaseException {
1008         ExternalReadEntry existing = null;
1009         synchronized(externalReadEntryMap) {
1010             existing = (ExternalReadEntry)externalReadEntryMap.get(r);
1011             if(existing == null) {
1012                 existing = new ExternalReadEntry(r);
1013                 existing.clearResult(querySupport);
1014                 existing.setPending();
1015                 externalReadEntryMap.put(id(r), existing);
1016                 size++;
1017                 return existing;
1018             }
1019             if(existing.requiresComputation()) {
1020                 existing.setPending();
1021                 return existing;
1022             }
1023         }
1024         if(existing.isPending()) waitPending(processor, existing);
1025         return existing;
1026     }
1027     
1028     void remove(ExternalReadEntry entry) {
1029         synchronized(externalReadEntryMap) {
1030             externalReadEntryMap.remove(entry.request);
1031         }
1032     }
1033     
1034     public static void runnerExternalReadEntry(ReadGraphImpl graph, ExternalRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure) throws DatabaseException {
1035         QueryCache cache  = graph.processor.cache;
1036         ExternalReadEntry entry = (ExternalReadEntry)cache.getOrCreateExternalReadEntry(graph.processor, r);
1037         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureExternalReadEntry;
1038         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1039         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1040         else {
1041           assert(entry.isPending());
1042             entry.compute(graph, procedure_);
1043             if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1044         }
1045     }
1046     
1047 }