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