]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java
de942b90f8611c3fd01227c0acf6f7740e74dc4e
[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.procedure.SyncMultiProcedure;
14 import org.simantics.db.request.AsyncMultiRead;
15 import org.simantics.db.request.AsyncRead;
16 import org.simantics.db.request.ExternalRead;
17 import org.simantics.db.request.MultiRead;
18 import org.simantics.db.request.Read;
19
20 public class QueryCache extends QueryCacheBase {
21
22     private static final boolean SINGLE = true;
23
24     public QueryCache(QuerySupport querySupport, int threads) {
25         super(querySupport, threads);
26     }
27
28     Objects getOrCreateObjects(ReadGraphImpl graph, int r1, int r2) throws DatabaseException {
29         Objects existing = null;
30         synchronized(objectsMap) {
31             existing = (Objects)objectsMap.get(r1,r2);
32             if(existing == null) {
33                 existing = new Objects(r1,r2);
34                 existing.setPending(querySupport);
35                 objectsMap.put(keyR2(r1,r2), existing);
36                 size++;
37                 return existing;
38             }
39             if(existing.requiresComputation()) {
40                 existing.setPending(querySupport);
41                 return existing;
42             }
43         }
44         if(existing.isPending()) {
45           waitPending(graph, existing);
46         }
47         return existing;
48     }
49     
50     void remove(Objects entry) {
51         synchronized(objectsMap) {
52             objectsMap.remove(entry.id);
53         }
54     }
55     
56     public static void runnerObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
57         QueryCache cache  = graph.processor.cache;
58         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) {
59             if (SINGLE) {
60                 Objects e = cache.peekObjects(r1,r2);
61                 if (e != null && e.isReady()) {
62                     e.performFromCache(graph, procedure);
63                     return;
64                 }
65             }
66             Objects.computeForEach(graph, r1,r2, null, procedure);
67             return;
68         }
69         Objects entry = (Objects)cache.getOrCreateObjects(graph, r1,r2);
70         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureObjects;
71         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
72         if(entry.isReady()) entry.performFromCache(graph, procedure_);
73         else {
74           assert(entry.isPending());
75           Objects.computeForEach(graph, r1,r2, entry, procedure_);
76           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
77         }
78     }
79     
80     private Objects peekObjects(int r1, int r2) {
81         synchronized(objectsMap) {
82             return (Objects) objectsMap.get(r1,r2);
83         }
84     }
85     
86     Statements getOrCreateStatements(ReadGraphImpl graph, int r1, int r2) throws DatabaseException {
87         Statements existing = null;
88         synchronized(statementsMap) {
89             existing = (Statements)statementsMap.get(r1,r2);
90             if(existing == null) {
91                 existing = new Statements(r1,r2);
92                 existing.setPending(querySupport);
93                 statementsMap.put(keyR2(r1,r2), existing);
94                 size++;
95                 return existing;
96             }
97             if(existing.requiresComputation()) {
98                 existing.setPending(querySupport);
99                 return existing;
100             }
101         }
102         if(existing.isPending()) {
103           waitPending(graph, existing);
104         }
105         return existing;
106     }
107     
108     void remove(Statements entry) {
109         synchronized(statementsMap) {
110             statementsMap.remove(entry.id);
111         }
112     }
113     
114     public static void runnerStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final TripleIntProcedure procedure) throws DatabaseException {
115         QueryCache cache  = graph.processor.cache;
116         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) {
117             if (SINGLE) {
118                 Statements e = cache.peekStatements(r1,r2);
119                 if (e != null && e.isReady()) {
120                     e.performFromCache(graph, procedure);
121                     return;
122                 }
123             }
124             Statements.computeForEach(graph, r1,r2, null, procedure);
125             return;
126         }
127         Statements entry = (Statements)cache.getOrCreateStatements(graph, r1,r2);
128         TripleIntProcedure procedure_ = procedure != null ? procedure : emptyProcedureStatements;
129         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
130         if(entry.isReady()) entry.performFromCache(graph, procedure_);
131         else {
132           assert(entry.isPending());
133           Statements.computeForEach(graph, r1,r2, entry, procedure_);
134           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
135         }
136     }
137     
138     private Statements peekStatements(int r1, int r2) {
139         synchronized(statementsMap) {
140             return (Statements) statementsMap.get(r1,r2);
141         }
142     }
143     
144     DirectObjects getOrCreateDirectObjects(ReadGraphImpl graph, int r1, int r2) throws DatabaseException {
145         DirectObjects existing = null;
146         synchronized(directObjectsMap) {
147             existing = (DirectObjects)directObjectsMap.get(r1,r2);
148             if(existing == null) {
149                 existing = new DirectObjects(r1,r2);
150                 existing.setPending(querySupport);
151                 directObjectsMap.put(keyR2(r1,r2), existing);
152                 size++;
153                 return existing;
154             }
155             if(existing.requiresComputation()) {
156                 existing.setPending(querySupport);
157                 return existing;
158             }
159         }
160         if(existing.isPending()) {
161           waitPending(graph, existing);
162         }
163         return existing;
164     }
165     
166     void remove(DirectObjects entry) {
167         synchronized(directObjectsMap) {
168             directObjectsMap.remove(entry.id);
169         }
170     }
171     
172     public static void runnerDirectObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
173         QueryCache cache  = graph.processor.cache;
174         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) {
175             if (SINGLE) {
176                 DirectObjects e = cache.peekDirectObjects(r1,r2);
177                 if (e != null && e.isReady()) {
178                     e.performFromCache(graph, procedure);
179                     return;
180                 }
181             }
182             DirectObjects.computeForEach(graph, r1,r2, null, procedure);
183             return;
184         }
185         DirectObjects entry = (DirectObjects)cache.getOrCreateDirectObjects(graph, r1,r2);
186         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureDirectObjects;
187         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
188         if(entry.isReady()) entry.performFromCache(graph, procedure_);
189         else {
190           assert(entry.isPending());
191           DirectObjects.computeForEach(graph, r1,r2, entry, procedure_);
192           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
193         }
194     }
195     
196     private DirectObjects peekDirectObjects(int r1, int r2) {
197         synchronized(directObjectsMap) {
198             return (DirectObjects) directObjectsMap.get(r1,r2);
199         }
200     }
201     
202     RelationInfoQuery getOrCreateRelationInfoQuery(ReadGraphImpl graph, int r) throws DatabaseException {
203         RelationInfoQuery existing = null;
204         synchronized(relationInfoQueryMap) {
205             existing = (RelationInfoQuery)relationInfoQueryMap.get(r);
206             if(existing == null) {
207                 existing = new RelationInfoQuery(r);
208                 existing.setPending(querySupport);
209                 relationInfoQueryMap.put(keyR(r), existing);
210                 size++;
211                 return existing;
212             }
213             if(existing.requiresComputation()) {
214                 existing.setPending(querySupport);
215                 return existing;
216             }
217         }
218         if(existing.isPending()) {
219           waitPending(graph, existing);
220         }
221         return existing;
222     }
223     
224     void remove(RelationInfoQuery entry) {
225         synchronized(relationInfoQueryMap) {
226             relationInfoQueryMap.remove(entry.id);
227         }
228     }
229     
230     public static void runnerRelationInfoQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<RelationInfo> procedure) throws DatabaseException {
231         QueryCache cache  = graph.processor.cache;
232         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
233             if (SINGLE) {
234                 RelationInfoQuery e = cache.peekRelationInfoQuery(r);
235                 if (e != null && e.isReady()) {
236                     e.performFromCache(graph, procedure);
237                     return;
238                 }
239             }
240             RelationInfoQuery.computeForEach(graph, r, null, procedure);
241             return;
242         }
243         RelationInfoQuery entry = (RelationInfoQuery)cache.getOrCreateRelationInfoQuery(graph, r);
244         InternalProcedure<RelationInfo> procedure_ = procedure != null ? procedure : emptyProcedureRelationInfoQuery;
245         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
246         if(entry.isReady()) entry.performFromCache(graph, procedure_);
247         else {
248           assert(entry.isPending());
249           RelationInfoQuery.computeForEach(graph, r, entry, procedure_);
250           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
251         }
252     }
253     
254     private RelationInfoQuery peekRelationInfoQuery(int r) {
255         synchronized(relationInfoQueryMap) {
256             return (RelationInfoQuery) relationInfoQueryMap.get(r);
257         }
258     }
259     
260     URIToResource getOrCreateURIToResource(ReadGraphImpl graph, String id) throws DatabaseException {
261         URIToResource existing = null;
262         synchronized(uRIToResourceMap) {
263             existing = (URIToResource)uRIToResourceMap.get(id);
264             if(existing == null) {
265                 existing = new URIToResource(id);
266                 existing.setPending(querySupport);
267                 uRIToResourceMap.put(keyID(id), existing);
268                 size++;
269                 return existing;
270             }
271             if(existing.requiresComputation()) {
272                 existing.setPending(querySupport);
273                 return existing;
274             }
275         }
276         if(existing.isPending()) {
277           waitPending(graph, existing);
278         }
279         return existing;
280     }
281     
282     void remove(URIToResource entry) {
283         synchronized(uRIToResourceMap) {
284             uRIToResourceMap.remove(entry.id);
285         }
286     }
287     
288     public static void runnerURIToResource(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener, final InternalProcedure<Integer> procedure) throws DatabaseException {
289         QueryCache cache  = graph.processor.cache;
290         if(parent == null && listener == null && !cache.shouldCache(graph.processor, id)) {
291             if (SINGLE) {
292                 URIToResource e = cache.peekURIToResource(id);
293                 if (e != null && e.isReady()) {
294                     e.performFromCache(graph, procedure);
295                     return;
296                 }
297             }
298             URIToResource.computeForEach(graph, id, null, procedure);
299             return;
300         }
301         URIToResource entry = (URIToResource)cache.getOrCreateURIToResource(graph, id);
302         InternalProcedure<Integer> procedure_ = procedure != null ? procedure : emptyProcedureURIToResource;
303         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
304         if(entry.isReady()) entry.performFromCache(graph, procedure_);
305         else {
306           assert(entry.isPending());
307           URIToResource.computeForEach(graph, id, entry, procedure_);
308           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
309         }
310     }
311     
312     private URIToResource peekURIToResource(String id) {
313         synchronized(uRIToResourceMap) {
314             return (URIToResource) uRIToResourceMap.get(id);
315         }
316     }
317     
318     ValueQuery getOrCreateValueQuery(ReadGraphImpl graph, int r) throws DatabaseException {
319         ValueQuery existing = null;
320         synchronized(valueQueryMap) {
321             existing = (ValueQuery)valueQueryMap.get(r);
322             if(existing == null) {
323                 existing = new ValueQuery(r);
324                 existing.setPending(querySupport);
325                 valueQueryMap.put(keyR(r), existing);
326                 size++;
327                 return existing;
328             }
329             if(existing.requiresComputation()) {
330                 existing.setPending(querySupport);
331                 return existing;
332             }
333         }
334         if(existing.isPending()) {
335           waitPending(graph, existing);
336         }
337         return existing;
338     }
339     
340     void remove(ValueQuery entry) {
341         synchronized(valueQueryMap) {
342             valueQueryMap.remove(entry.id);
343         }
344     }
345     
346     public static void runnerValueQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<byte[]> procedure) throws DatabaseException {
347         QueryCache cache  = graph.processor.cache;
348         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
349             if (SINGLE) {
350                 ValueQuery e = cache.peekValueQuery(r);
351                 if (e != null && e.isReady()) {
352                     e.performFromCache(graph, procedure);
353                     return;
354                 }
355             }
356             ValueQuery.computeForEach(graph, r, null, procedure);
357             return;
358         }
359         ValueQuery entry = (ValueQuery)cache.getOrCreateValueQuery(graph, r);
360         InternalProcedure<byte[]> procedure_ = procedure != null ? procedure : emptyProcedureValueQuery;
361         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
362         if(entry.isReady()) entry.performFromCache(graph, procedure_);
363         else {
364           assert(entry.isPending());
365           ValueQuery.computeForEach(graph, r, entry, procedure_);
366           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
367         }
368     }
369     
370     private ValueQuery peekValueQuery(int r) {
371         synchronized(valueQueryMap) {
372             return (ValueQuery) valueQueryMap.get(r);
373         }
374     }
375     
376     OrderedSet getOrCreateOrderedSet(ReadGraphImpl graph, int r) throws DatabaseException {
377         OrderedSet existing = null;
378         synchronized(orderedSetMap) {
379             existing = (OrderedSet)orderedSetMap.get(r);
380             if(existing == null) {
381                 existing = new OrderedSet(r);
382                 existing.setPending(querySupport);
383                 orderedSetMap.put(keyR(r), existing);
384                 size++;
385                 return existing;
386             }
387             if(existing.requiresComputation()) {
388                 existing.setPending(querySupport);
389                 return existing;
390             }
391         }
392         if(existing.isPending()) {
393           waitPending(graph, existing);
394         }
395         return existing;
396     }
397     
398     void remove(OrderedSet entry) {
399         synchronized(orderedSetMap) {
400             orderedSetMap.remove(entry.id);
401         }
402     }
403     
404     public static void runnerOrderedSet(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
405         QueryCache cache  = graph.processor.cache;
406         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
407             if (SINGLE) {
408                 OrderedSet e = cache.peekOrderedSet(r);
409                 if (e != null && e.isReady()) {
410                     e.performFromCache(graph, procedure);
411                     return;
412                 }
413             }
414             OrderedSet.computeForEach(graph, r, null, procedure);
415             return;
416         }
417         OrderedSet entry = (OrderedSet)cache.getOrCreateOrderedSet(graph, r);
418         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureOrderedSet;
419         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
420         if(entry.isReady()) entry.performFromCache(graph, procedure_);
421         else {
422           assert(entry.isPending());
423           OrderedSet.computeForEach(graph, r, entry, procedure_);
424           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
425         }
426     }
427     
428     private OrderedSet peekOrderedSet(int r) {
429         synchronized(orderedSetMap) {
430             return (OrderedSet) orderedSetMap.get(r);
431         }
432     }
433     
434     PrincipalTypes getOrCreatePrincipalTypes(ReadGraphImpl graph, int r) throws DatabaseException {
435         PrincipalTypes existing = null;
436         synchronized(principalTypesMap) {
437             existing = (PrincipalTypes)principalTypesMap.get(r);
438             if(existing == null) {
439                 existing = new PrincipalTypes(r);
440                 existing.setPending(querySupport);
441                 principalTypesMap.put(keyR(r), existing);
442                 size++;
443                 return existing;
444             }
445             if(existing.requiresComputation()) {
446                 existing.setPending(querySupport);
447                 return existing;
448             }
449         }
450         if(existing.isPending()) {
451           waitPending(graph, existing);
452         }
453         return existing;
454     }
455     
456     void remove(PrincipalTypes entry) {
457         synchronized(principalTypesMap) {
458             principalTypesMap.remove(entry.id);
459         }
460     }
461     
462     public static void runnerPrincipalTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
463         QueryCache cache  = graph.processor.cache;
464         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
465             if (SINGLE) {
466                 PrincipalTypes e = cache.peekPrincipalTypes(r);
467                 if (e != null && e.isReady()) {
468                     e.performFromCache(graph, procedure);
469                     return;
470                 }
471             }
472             PrincipalTypes.computeForEach(graph, r, null, procedure);
473             return;
474         }
475         PrincipalTypes entry = (PrincipalTypes)cache.getOrCreatePrincipalTypes(graph, r);
476         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedurePrincipalTypes;
477         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
478         if(entry.isReady()) entry.performFromCache(graph, procedure_);
479         else {
480           assert(entry.isPending());
481           PrincipalTypes.computeForEach(graph, r, entry, procedure_);
482           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
483         }
484     }
485     
486     private PrincipalTypes peekPrincipalTypes(int r) {
487         synchronized(principalTypesMap) {
488             return (PrincipalTypes) principalTypesMap.get(r);
489         }
490     }
491     
492     DirectPredicates getOrCreateDirectPredicates(ReadGraphImpl graph, int r) throws DatabaseException {
493         DirectPredicates existing = null;
494         synchronized(directPredicatesMap) {
495             existing = (DirectPredicates)directPredicatesMap.get(r);
496             if(existing == null) {
497                 existing = new DirectPredicates(r);
498                 existing.setPending(querySupport);
499                 directPredicatesMap.put(keyR(r), existing);
500                 size++;
501                 return existing;
502             }
503             if(existing.requiresComputation()) {
504                 existing.setPending(querySupport);
505                 return existing;
506             }
507         }
508         if(existing.isPending()) {
509           waitPending(graph, existing);
510         }
511         return existing;
512     }
513     
514     void remove(DirectPredicates entry) {
515         synchronized(directPredicatesMap) {
516             directPredicatesMap.remove(entry.id);
517         }
518     }
519     
520     public static void runnerDirectPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
521         QueryCache cache  = graph.processor.cache;
522         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
523             if (SINGLE) {
524                 DirectPredicates e = cache.peekDirectPredicates(r);
525                 if (e != null && e.isReady()) {
526                     e.performFromCache(graph, procedure);
527                     return;
528                 }
529             }
530             DirectPredicates.computeForEach(graph, r, null, procedure);
531             return;
532         }
533         DirectPredicates entry = (DirectPredicates)cache.getOrCreateDirectPredicates(graph, r);
534         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureDirectPredicates;
535         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
536         if(entry.isReady()) entry.performFromCache(graph, procedure_);
537         else {
538           assert(entry.isPending());
539           DirectPredicates.computeForEach(graph, r, entry, procedure_);
540           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
541         }
542     }
543     
544     private DirectPredicates peekDirectPredicates(int r) {
545         synchronized(directPredicatesMap) {
546             return (DirectPredicates) directPredicatesMap.get(r);
547         }
548     }
549     
550     Predicates getOrCreatePredicates(ReadGraphImpl graph, int r) throws DatabaseException {
551         Predicates existing = null;
552         synchronized(predicatesMap) {
553             existing = (Predicates)predicatesMap.get(r);
554             if(existing == null) {
555                 existing = new Predicates(r);
556                 existing.setPending(querySupport);
557                 predicatesMap.put(keyR(r), existing);
558                 size++;
559                 return existing;
560             }
561             if(existing.requiresComputation()) {
562                 existing.setPending(querySupport);
563                 return existing;
564             }
565         }
566         if(existing.isPending()) {
567           waitPending(graph, existing);
568         }
569         return existing;
570     }
571     
572     void remove(Predicates entry) {
573         synchronized(predicatesMap) {
574             predicatesMap.remove(entry.id);
575         }
576     }
577     
578     public static void runnerPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
579         QueryCache cache  = graph.processor.cache;
580         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
581             if (SINGLE) {
582                 Predicates e = cache.peekPredicates(r);
583                 if (e != null && e.isReady()) {
584                     e.performFromCache(graph, procedure);
585                     return;
586                 }
587             }
588             Predicates.computeForEach(graph, r, null, procedure);
589             return;
590         }
591         Predicates entry = (Predicates)cache.getOrCreatePredicates(graph, r);
592         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedurePredicates;
593         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
594         if(entry.isReady()) entry.performFromCache(graph, procedure_);
595         else {
596           assert(entry.isPending());
597           Predicates.computeForEach(graph, r, entry, procedure_);
598           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
599         }
600     }
601     
602     private Predicates peekPredicates(int r) {
603         synchronized(predicatesMap) {
604             return (Predicates) predicatesMap.get(r);
605         }
606     }
607     
608     ReadEntry getOrCreateReadEntry(ReadGraphImpl graph, Read<?> r, boolean needsToBlock) throws DatabaseException {
609         ReadEntry existing = null;
610         synchronized(readEntryMap) {
611             existing = (ReadEntry)readEntryMap.get(r);
612             if(existing == null) {
613                 existing = new ReadEntry(r);
614                 existing.setPending(querySupport);
615                 readEntryMap.put(id(r), existing);
616                 size++;
617                 return existing;
618             }
619             if(existing.requiresComputation()) {
620                 existing.setPending(querySupport);
621                 return existing;
622             }
623         }
624         if(existing.isPending()) {
625           if(needsToBlock)
626             waitPending(graph, existing);
627           else {
628             return null;
629           }
630         }
631         return existing;
632     }
633     
634     void remove(ReadEntry entry) {
635         synchronized(readEntryMap) {
636             readEntryMap.remove(entry.id);
637         }
638     }
639     
640     public static Object runnerReadEntry(ReadGraphImpl graph, Read<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure, boolean needsToBlock) throws DatabaseException {
641         QueryCache cache  = graph.processor.cache;
642         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
643             if (SINGLE) {
644                 ReadEntry e = cache.peekReadEntry(r);
645                 if (e != null && e.isReady()) {
646                     return e.performFromCache(graph, procedure);
647                 }
648             }
649             return ReadEntry.computeForEach(graph, r, null, procedure, needsToBlock);
650         }
651         ReadEntry entry = (ReadEntry)cache.getOrCreateReadEntry(graph, r, needsToBlock);
652         if(entry == null) {
653           graph.processor.schedule(new SessionTask(graph) {
654             @Override
655             public void run0(int thread) {
656               try {
657                 runnerReadEntry(graph, r, parent, listener, procedure, needsToBlock);
658               } catch (DatabaseException e) {
659                 Logger.defaultLogError(e);
660               }
661             }
662           });
663           return null;
664         }
665         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureReadEntry;
666         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
667         if(entry.isReady()) return entry.performFromCache(graph, procedure_);
668         else {
669           assert(entry.isPending());
670           Object result = ReadEntry.computeForEach(graph, r, entry, procedure_, needsToBlock);
671           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
672           return result;
673         }
674     }
675     
676     private ReadEntry peekReadEntry(Read<?> r) {
677         synchronized(readEntryMap) {
678             return (ReadEntry) readEntryMap.get(r);
679         }
680     }
681     
682     AsyncReadEntry getOrCreateAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, boolean needsToBlock) throws DatabaseException {
683         AsyncReadEntry existing = null;
684         synchronized(asyncReadEntryMap) {
685             existing = (AsyncReadEntry)asyncReadEntryMap.get(r);
686             if(existing == null) {
687                 existing = new AsyncReadEntry(r);
688                 existing.setPending(querySupport);
689                 asyncReadEntryMap.put(id(r), existing);
690                 size++;
691                 return existing;
692             }
693             if(existing.requiresComputation()) {
694                 existing.setPending(querySupport);
695                 return existing;
696             }
697         }
698         if(existing.isPending()) {
699           if(needsToBlock)
700             waitPending(graph, existing);
701           else {
702             return null;
703           }
704         }
705         return existing;
706     }
707     
708     void remove(AsyncReadEntry entry) {
709         synchronized(asyncReadEntryMap) {
710             asyncReadEntryMap.remove(entry.id);
711         }
712     }
713     
714     public static Object runnerAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure, boolean needsToBlock) throws DatabaseException {
715         QueryCache cache  = graph.processor.cache;
716         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
717             if (SINGLE) {
718                 AsyncReadEntry e = cache.peekAsyncReadEntry(r);
719                 if (e != null && e.isReady()) {
720                     return e.performFromCache(graph, procedure);
721                 }
722             }
723             return AsyncReadEntry.computeForEach(graph, r, null, procedure, needsToBlock);
724         }
725         AsyncReadEntry entry = (AsyncReadEntry)cache.getOrCreateAsyncReadEntry(graph, r, needsToBlock);
726         if(entry == null) {
727           graph.processor.schedule(new SessionTask(graph) {
728             @Override
729             public void run0(int thread) {
730               try {
731                 runnerAsyncReadEntry(graph, r, parent, listener, procedure, needsToBlock);
732               } catch (DatabaseException e) {
733                 Logger.defaultLogError(e);
734               }
735             }
736           });
737           return null;
738         }
739         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureAsyncReadEntry;
740         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
741         if(entry.isReady()) return entry.performFromCache(graph, procedure_);
742         else {
743           assert(entry.isPending());
744           Object result = AsyncReadEntry.computeForEach(graph, r, entry, procedure_, needsToBlock);
745           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
746           return result;
747         }
748     }
749     
750     private AsyncReadEntry peekAsyncReadEntry(AsyncRead<?> r) {
751         synchronized(asyncReadEntryMap) {
752             return (AsyncReadEntry) asyncReadEntryMap.get(r);
753         }
754     }
755     
756     Types getOrCreateTypes(ReadGraphImpl graph, int r) throws DatabaseException {
757         Types existing = null;
758         synchronized(typesMap) {
759             existing = (Types)typesMap.get(r);
760             if(existing == null) {
761                 existing = new Types(r);
762                 existing.setPending(querySupport);
763                 typesMap.put(keyR(r), existing);
764                 size++;
765                 return existing;
766             }
767             if(existing.requiresComputation()) {
768                 existing.setPending(querySupport);
769                 return existing;
770             }
771         }
772         if(existing.isPending()) {
773           waitPending(graph, existing);
774         }
775         return existing;
776     }
777     
778     void remove(Types entry) {
779         synchronized(typesMap) {
780             typesMap.remove(entry.id);
781         }
782     }
783     
784     public static void runnerTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
785         QueryCache cache  = graph.processor.cache;
786         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
787             if (SINGLE) {
788                 Types e = cache.peekTypes(r);
789                 if (e != null && e.isReady()) {
790                     e.performFromCache(graph, procedure);
791                     return;
792                 }
793             }
794             Types.computeForEach(graph, r, null, procedure);
795             return;
796         }
797         Types entry = (Types)cache.getOrCreateTypes(graph, r);
798         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureTypes;
799         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
800         if(entry.isReady()) entry.performFromCache(graph, procedure_);
801         else {
802           assert(entry.isPending());
803           Types.computeForEach(graph, r, entry, procedure_);
804           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
805         }
806     }
807     
808     private Types peekTypes(int r) {
809         synchronized(typesMap) {
810             return (Types) typesMap.get(r);
811         }
812     }
813     
814     ChildMap getOrCreateChildMap(ReadGraphImpl graph, int r) throws DatabaseException {
815         ChildMap existing = null;
816         synchronized(childMapMap) {
817             existing = (ChildMap)childMapMap.get(r);
818             if(existing == null) {
819                 existing = new ChildMap(r);
820                 existing.setPending(querySupport);
821                 childMapMap.put(keyR(r), existing);
822                 size++;
823                 return existing;
824             }
825             if(existing.requiresComputation()) {
826                 existing.setPending(querySupport);
827                 return existing;
828             }
829         }
830         if(existing.isPending()) {
831           waitPending(graph, existing);
832         }
833         return existing;
834     }
835     
836     void remove(ChildMap entry) {
837         synchronized(childMapMap) {
838             childMapMap.remove(entry.id);
839         }
840     }
841     
842     public static void runnerChildMap(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<ObjectResourceIdMap<String>> procedure) throws DatabaseException {
843         QueryCache cache  = graph.processor.cache;
844         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
845             if (SINGLE) {
846                 ChildMap e = cache.peekChildMap(r);
847                 if (e != null && e.isReady()) {
848                     e.performFromCache(graph, procedure);
849                     return;
850                 }
851             }
852             ChildMap.computeForEach(graph, r, null, procedure);
853             return;
854         }
855         ChildMap entry = (ChildMap)cache.getOrCreateChildMap(graph, r);
856         InternalProcedure<ObjectResourceIdMap<String>> procedure_ = procedure != null ? procedure : emptyProcedureChildMap;
857         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
858         if(entry.isReady()) entry.performFromCache(graph, procedure_);
859         else {
860           assert(entry.isPending());
861           ChildMap.computeForEach(graph, r, entry, procedure_);
862           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
863         }
864     }
865     
866     private ChildMap peekChildMap(int r) {
867         synchronized(childMapMap) {
868             return (ChildMap) childMapMap.get(r);
869         }
870     }
871     
872     TypeHierarchy getOrCreateTypeHierarchy(ReadGraphImpl graph, int r) throws DatabaseException {
873         TypeHierarchy existing = null;
874         synchronized(typeHierarchyMap) {
875             existing = (TypeHierarchy)typeHierarchyMap.get(r);
876             if(existing == null) {
877                 existing = new TypeHierarchy(r);
878                 existing.setPending(querySupport);
879                 typeHierarchyMap.put(keyR(r), existing);
880                 size++;
881                 return existing;
882             }
883             if(existing.requiresComputation()) {
884                 existing.setPending(querySupport);
885                 return existing;
886             }
887         }
888         if(existing.isPending()) {
889           waitPending(graph, existing);
890         }
891         return existing;
892     }
893     
894     void remove(TypeHierarchy entry) {
895         synchronized(typeHierarchyMap) {
896             typeHierarchyMap.remove(entry.id);
897         }
898     }
899     
900     public static void runnerTypeHierarchy(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
901         QueryCache cache  = graph.processor.cache;
902         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
903             if (SINGLE) {
904                 TypeHierarchy e = cache.peekTypeHierarchy(r);
905                 if (e != null && e.isReady()) {
906                     e.performFromCache(graph, procedure);
907                     return;
908                 }
909             }
910             TypeHierarchy.computeForEach(graph, r, null, procedure);
911             return;
912         }
913         TypeHierarchy entry = (TypeHierarchy)cache.getOrCreateTypeHierarchy(graph, r);
914         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureTypeHierarchy;
915         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
916         if(entry.isReady()) entry.performFromCache(graph, procedure_);
917         else {
918           assert(entry.isPending());
919           TypeHierarchy.computeForEach(graph, r, entry, procedure_);
920           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
921         }
922     }
923     
924     private TypeHierarchy peekTypeHierarchy(int r) {
925         synchronized(typeHierarchyMap) {
926             return (TypeHierarchy) typeHierarchyMap.get(r);
927         }
928     }
929     
930     SuperTypes getOrCreateSuperTypes(ReadGraphImpl graph, int r) throws DatabaseException {
931         SuperTypes existing = null;
932         synchronized(superTypesMap) {
933             existing = (SuperTypes)superTypesMap.get(r);
934             if(existing == null) {
935                 existing = new SuperTypes(r);
936                 existing.setPending(querySupport);
937                 superTypesMap.put(keyR(r), existing);
938                 size++;
939                 return existing;
940             }
941             if(existing.requiresComputation()) {
942                 existing.setPending(querySupport);
943                 return existing;
944             }
945         }
946         if(existing.isPending()) {
947           waitPending(graph, existing);
948         }
949         return existing;
950     }
951     
952     void remove(SuperTypes entry) {
953         synchronized(superTypesMap) {
954             superTypesMap.remove(entry.id);
955         }
956     }
957     
958     public static void runnerSuperTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
959         QueryCache cache  = graph.processor.cache;
960         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
961             if (SINGLE) {
962                 SuperTypes e = cache.peekSuperTypes(r);
963                 if (e != null && e.isReady()) {
964                     e.performFromCache(graph, procedure);
965                     return;
966                 }
967             }
968             SuperTypes.computeForEach(graph, r, null, procedure);
969             return;
970         }
971         SuperTypes entry = (SuperTypes)cache.getOrCreateSuperTypes(graph, r);
972         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureSuperTypes;
973         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
974         if(entry.isReady()) entry.performFromCache(graph, procedure_);
975         else {
976           assert(entry.isPending());
977           SuperTypes.computeForEach(graph, r, entry, procedure_);
978           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
979         }
980     }
981     
982     private SuperTypes peekSuperTypes(int r) {
983         synchronized(superTypesMap) {
984             return (SuperTypes) superTypesMap.get(r);
985         }
986     }
987     
988     SuperRelations getOrCreateSuperRelations(ReadGraphImpl graph, int r) throws DatabaseException {
989         SuperRelations existing = null;
990         synchronized(superRelationsMap) {
991             existing = (SuperRelations)superRelationsMap.get(r);
992             if(existing == null) {
993                 existing = new SuperRelations(r);
994                 existing.setPending(querySupport);
995                 superRelationsMap.put(keyR(r), existing);
996                 size++;
997                 return existing;
998             }
999             if(existing.requiresComputation()) {
1000                 existing.setPending(querySupport);
1001                 return existing;
1002             }
1003         }
1004         if(existing.isPending()) {
1005           waitPending(graph, existing);
1006         }
1007         return existing;
1008     }
1009     
1010     void remove(SuperRelations entry) {
1011         synchronized(superRelationsMap) {
1012             superRelationsMap.remove(entry.id);
1013         }
1014     }
1015     
1016     public static void runnerSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
1017         QueryCache cache  = graph.processor.cache;
1018         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
1019             if (SINGLE) {
1020                 SuperRelations e = cache.peekSuperRelations(r);
1021                 if (e != null && e.isReady()) {
1022                     e.performFromCache(graph, procedure);
1023                     return;
1024                 }
1025             }
1026             SuperRelations.computeForEach(graph, r, null, procedure);
1027             return;
1028         }
1029         SuperRelations entry = (SuperRelations)cache.getOrCreateSuperRelations(graph, r);
1030         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureSuperRelations;
1031         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1032         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1033         else {
1034           assert(entry.isPending());
1035           SuperRelations.computeForEach(graph, r, entry, procedure_);
1036           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1037         }
1038     }
1039     
1040     private SuperRelations peekSuperRelations(int r) {
1041         synchronized(superRelationsMap) {
1042             return (SuperRelations) superRelationsMap.get(r);
1043         }
1044     }
1045     
1046     AssertedPredicates getOrCreateAssertedPredicates(ReadGraphImpl graph, int r) throws DatabaseException {
1047         AssertedPredicates existing = null;
1048         synchronized(assertedPredicatesMap) {
1049             existing = (AssertedPredicates)assertedPredicatesMap.get(r);
1050             if(existing == null) {
1051                 existing = new AssertedPredicates(r);
1052                 existing.setPending(querySupport);
1053                 assertedPredicatesMap.put(keyR(r), existing);
1054                 size++;
1055                 return existing;
1056             }
1057             if(existing.requiresComputation()) {
1058                 existing.setPending(querySupport);
1059                 return existing;
1060             }
1061         }
1062         if(existing.isPending()) {
1063           waitPending(graph, existing);
1064         }
1065         return existing;
1066     }
1067     
1068     void remove(AssertedPredicates entry) {
1069         synchronized(assertedPredicatesMap) {
1070             assertedPredicatesMap.remove(entry.id);
1071         }
1072     }
1073     
1074     public static void runnerAssertedPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
1075         QueryCache cache  = graph.processor.cache;
1076         AssertedPredicates entry = (AssertedPredicates)cache.getOrCreateAssertedPredicates(graph, r);
1077         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureAssertedPredicates;
1078         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1079         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1080         else {
1081           assert(entry.isPending());
1082           entry.compute(graph, procedure_);
1083           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1084         }
1085     }
1086     
1087     private AssertedPredicates peekAssertedPredicates(int r) {
1088         synchronized(assertedPredicatesMap) {
1089             return (AssertedPredicates) assertedPredicatesMap.get(r);
1090         }
1091     }
1092     
1093     AssertedStatements getOrCreateAssertedStatements(ReadGraphImpl graph, int r1, int r2) throws DatabaseException {
1094         AssertedStatements existing = null;
1095         synchronized(assertedStatementsMap) {
1096             existing = (AssertedStatements)assertedStatementsMap.get(r1,r2);
1097             if(existing == null) {
1098                 existing = new AssertedStatements(r1,r2);
1099                 existing.setPending(querySupport);
1100                 assertedStatementsMap.put(keyR2(r1,r2), existing);
1101                 size++;
1102                 return existing;
1103             }
1104             if(existing.requiresComputation()) {
1105                 existing.setPending(querySupport);
1106                 return existing;
1107             }
1108         }
1109         if(existing.isPending()) {
1110           waitPending(graph, existing);
1111         }
1112         return existing;
1113     }
1114     
1115     void remove(AssertedStatements entry) {
1116         synchronized(assertedStatementsMap) {
1117             assertedStatementsMap.remove(entry.id);
1118         }
1119     }
1120     
1121     public static void runnerAssertedStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final TripleIntProcedure procedure) throws DatabaseException {
1122         QueryCache cache  = graph.processor.cache;
1123         AssertedStatements entry = (AssertedStatements)cache.getOrCreateAssertedStatements(graph, r1,r2);
1124         TripleIntProcedure procedure_ = procedure != null ? procedure : emptyProcedureAssertedStatements;
1125         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1126         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1127         else {
1128           assert(entry.isPending());
1129           entry.compute(graph, procedure_);
1130           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1131         }
1132     }
1133     
1134     private AssertedStatements peekAssertedStatements(int r1, int r2) {
1135         synchronized(assertedStatementsMap) {
1136             return (AssertedStatements) assertedStatementsMap.get(r1,r2);
1137         }
1138     }
1139     
1140     DirectSuperRelations getOrCreateDirectSuperRelations(ReadGraphImpl graph, int r) throws DatabaseException {
1141         DirectSuperRelations existing = null;
1142         synchronized(directSuperRelationsMap) {
1143             existing = (DirectSuperRelations)directSuperRelationsMap.get(r);
1144             if(existing == null) {
1145                 existing = new DirectSuperRelations(r);
1146                 existing.setPending(querySupport);
1147                 directSuperRelationsMap.put(keyR(r), existing);
1148                 size++;
1149                 return existing;
1150             }
1151             if(existing.requiresComputation()) {
1152                 existing.setPending(querySupport);
1153                 return existing;
1154             }
1155         }
1156         if(existing.isPending()) {
1157           waitPending(graph, existing);
1158         }
1159         return existing;
1160     }
1161     
1162     void remove(DirectSuperRelations entry) {
1163         synchronized(directSuperRelationsMap) {
1164             directSuperRelationsMap.remove(entry.id);
1165         }
1166     }
1167     
1168     public static void runnerDirectSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
1169         QueryCache cache  = graph.processor.cache;
1170         DirectSuperRelations entry = (DirectSuperRelations)cache.getOrCreateDirectSuperRelations(graph, r);
1171         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureDirectSuperRelations;
1172         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1173         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1174         else {
1175           assert(entry.isPending());
1176           entry.compute(graph, procedure_);
1177           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1178         }
1179     }
1180     
1181     private DirectSuperRelations peekDirectSuperRelations(int r) {
1182         synchronized(directSuperRelationsMap) {
1183             return (DirectSuperRelations) directSuperRelationsMap.get(r);
1184         }
1185     }
1186     
1187     MultiReadEntry getOrCreateMultiReadEntry(ReadGraphImpl graph, MultiRead<?> r) throws DatabaseException {
1188         MultiReadEntry existing = null;
1189         synchronized(multiReadEntryMap) {
1190             existing = (MultiReadEntry)multiReadEntryMap.get(r);
1191             if(existing == null) {
1192                 existing = new MultiReadEntry(r);
1193                 existing.setPending(querySupport);
1194                 multiReadEntryMap.put(id(r), existing);
1195                 size++;
1196                 return existing;
1197             }
1198             if(existing.requiresComputation()) {
1199                 existing.setPending(querySupport);
1200                 return existing;
1201             }
1202         }
1203         if(existing.isPending()) {
1204           waitPending(graph, existing);
1205         }
1206         return existing;
1207     }
1208     
1209     void remove(MultiReadEntry entry) {
1210         synchronized(multiReadEntryMap) {
1211             multiReadEntryMap.remove(entry.id);
1212         }
1213     }
1214     
1215     public static void runnerMultiReadEntry(ReadGraphImpl graph, MultiRead<?> r, CacheEntry parent, ListenerBase listener, final SyncMultiProcedure procedure) throws DatabaseException {
1216         QueryCache cache  = graph.processor.cache;
1217         MultiReadEntry entry = (MultiReadEntry)cache.getOrCreateMultiReadEntry(graph, r);
1218         SyncMultiProcedure procedure_ = procedure != null ? procedure : emptyProcedureMultiReadEntry;
1219         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1220         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1221         else {
1222           assert(entry.isPending());
1223           entry.compute(graph, procedure_);
1224           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1225         }
1226     }
1227     
1228     private MultiReadEntry peekMultiReadEntry(MultiRead<?> r) {
1229         synchronized(multiReadEntryMap) {
1230             return (MultiReadEntry) multiReadEntryMap.get(r);
1231         }
1232     }
1233     
1234     AsyncMultiReadEntry getOrCreateAsyncMultiReadEntry(ReadGraphImpl graph, AsyncMultiRead<?> r) throws DatabaseException {
1235         AsyncMultiReadEntry existing = null;
1236         synchronized(asyncMultiReadEntryMap) {
1237             existing = (AsyncMultiReadEntry)asyncMultiReadEntryMap.get(r);
1238             if(existing == null) {
1239                 existing = new AsyncMultiReadEntry(r);
1240                 existing.setPending(querySupport);
1241                 asyncMultiReadEntryMap.put(id(r), existing);
1242                 size++;
1243                 return existing;
1244             }
1245             if(existing.requiresComputation()) {
1246                 existing.setPending(querySupport);
1247                 return existing;
1248             }
1249         }
1250         if(existing.isPending()) {
1251           waitPending(graph, existing);
1252         }
1253         return existing;
1254     }
1255     
1256     void remove(AsyncMultiReadEntry entry) {
1257         synchronized(asyncMultiReadEntryMap) {
1258             asyncMultiReadEntryMap.remove(entry.id);
1259         }
1260     }
1261     
1262     public static void runnerAsyncMultiReadEntry(ReadGraphImpl graph, AsyncMultiRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncMultiProcedure procedure) throws DatabaseException {
1263         QueryCache cache  = graph.processor.cache;
1264         AsyncMultiReadEntry entry = (AsyncMultiReadEntry)cache.getOrCreateAsyncMultiReadEntry(graph, r);
1265         AsyncMultiProcedure procedure_ = procedure != null ? procedure : emptyProcedureAsyncMultiReadEntry;
1266         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1267         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1268         else {
1269           assert(entry.isPending());
1270           entry.compute(graph, procedure_);
1271           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1272         }
1273     }
1274     
1275     private AsyncMultiReadEntry peekAsyncMultiReadEntry(AsyncMultiRead<?> r) {
1276         synchronized(asyncMultiReadEntryMap) {
1277             return (AsyncMultiReadEntry) asyncMultiReadEntryMap.get(r);
1278         }
1279     }
1280     
1281     ExternalReadEntry getOrCreateExternalReadEntry(ReadGraphImpl graph, ExternalRead<?> r) throws DatabaseException {
1282         ExternalReadEntry existing = null;
1283         synchronized(externalReadEntryMap) {
1284             existing = (ExternalReadEntry)externalReadEntryMap.get(r);
1285             if(existing == null) {
1286                 existing = new ExternalReadEntry(r, graph);
1287                 existing.setPending(querySupport);
1288                 externalReadEntryMap.put(id(r), existing);
1289                 size++;
1290                 return existing;
1291             }
1292             if(existing.requiresComputation()) {
1293                 existing.setPending(querySupport);
1294                 return existing;
1295             }
1296         }
1297         if(existing.isPending()) {
1298           waitPending(graph, existing);
1299         }
1300         return existing;
1301     }
1302     
1303     void remove(ExternalReadEntry entry) {
1304         synchronized(externalReadEntryMap) {
1305             externalReadEntryMap.remove(entry.id);
1306         }
1307     }
1308     
1309     public static void runnerExternalReadEntry(ReadGraphImpl graph, ExternalRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure) throws DatabaseException {
1310         QueryCache cache  = graph.processor.cache;
1311         ExternalReadEntry entry = (ExternalReadEntry)cache.getOrCreateExternalReadEntry(graph, r);
1312         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureExternalReadEntry;
1313         ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure_, false);
1314         if(entry.isReady()) entry.performFromCache(graph, procedure_);
1315         else {
1316           assert(entry.isPending());
1317           entry.compute(graph, procedure_);
1318           if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
1319         }
1320     }
1321     
1322     private ExternalReadEntry peekExternalReadEntry(ExternalRead<?> r) {
1323         synchronized(externalReadEntryMap) {
1324             return (ExternalReadEntry) externalReadEntryMap.get(r);
1325         }
1326     }
1327     
1328 }