]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java
cc0ca919b584942a4d49a1a4c61b97b741e631f2
[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     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.processor.scheduleNow(new SessionTask(graph) {
674             @Override
675             public void run0(int thread) {
676               try {
677                 runnerReadEntry(graph, r, parent, listener, procedure, needsToBlock);
678               } catch (DatabaseException e) {
679                 Logger.defaultLogError(e);
680               }
681             }
682           });
683           return null;
684         }
685         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureReadEntry;
686         if(entry.isReady()) {
687           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
688           Object result = entry.performFromCache(graph, procedure_);
689           graph.processor.listening.registerFirstKnown(listener, result);
690           return result;
691         }
692         else {
693           assert(entry.isPending());
694           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
695           Object result = ReadEntry.computeForEach(graph, r, entry, procedure_, needsToBlock);
696           graph.processor.listening.registerFirstKnown(listener, result);
697           return result;
698         }
699     }
700     
701     private ReadEntry peekReadEntry(Read<?> r) {
702         synchronized(readEntryMap) {
703             return (ReadEntry) readEntryMap.get(r);
704         }
705     }
706     
707     AsyncReadEntry getOrCreateAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, boolean needsToBlock) throws DatabaseException {
708         AsyncReadEntry existing = null;
709         synchronized(asyncReadEntryMap) {
710             existing = (AsyncReadEntry)asyncReadEntryMap.get(r);
711             if(existing == null) {
712                 existing = new AsyncReadEntry(r);
713                 existing.setPending(querySupport);
714                 asyncReadEntryMap.put(id(r), existing);
715                 size++;
716                 return existing;
717             }
718             if(existing.requiresComputation()) {
719                 existing.setPending(querySupport);
720                 return existing;
721             }
722         }
723         if(existing.isPending()) {
724           if(needsToBlock)
725             waitPending(graph, existing);
726           else {
727             return null;
728           }
729         }
730         return existing;
731     }
732     
733     void remove(AsyncReadEntry entry) {
734         synchronized(asyncReadEntryMap) {
735             asyncReadEntryMap.remove(entry.id);
736         }
737     }
738     
739     public static Object runnerAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure, boolean needsToBlock) throws DatabaseException {
740         QueryCache cache  = graph.processor.cache;
741         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
742             if (SINGLE) {
743                 AsyncReadEntry e = cache.peekAsyncReadEntry(r);
744                 if (e != null && e.isReady()) {
745                     return e.performFromCache(graph, procedure);
746                 }
747             }
748             return AsyncReadEntry.computeForEach(graph, r, null, procedure, needsToBlock);
749         }
750         AsyncReadEntry entry = (AsyncReadEntry)cache.getOrCreateAsyncReadEntry(graph, r, needsToBlock);
751         if(entry == null) {
752           graph.processor.scheduleNow(new SessionTask(graph) {
753             @Override
754             public void run0(int thread) {
755               try {
756                 runnerAsyncReadEntry(graph, r, parent, listener, procedure, needsToBlock);
757               } catch (DatabaseException e) {
758                 Logger.defaultLogError(e);
759               }
760             }
761           });
762           return null;
763         }
764         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureAsyncReadEntry;
765         if(entry.isReady()) {
766           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
767           Object result = entry.performFromCache(graph, procedure_);
768           graph.processor.listening.registerFirstKnown(listener, result);
769           return result;
770         }
771         else {
772           assert(entry.isPending());
773           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
774           Object result = AsyncReadEntry.computeForEach(graph, r, entry, procedure_, needsToBlock);
775           graph.processor.listening.registerFirstKnown(listener, result);
776           return result;
777         }
778     }
779     
780     private AsyncReadEntry peekAsyncReadEntry(AsyncRead<?> r) {
781         synchronized(asyncReadEntryMap) {
782             return (AsyncReadEntry) asyncReadEntryMap.get(r);
783         }
784     }
785     
786     Types getOrCreateTypes(ReadGraphImpl graph, int r) throws DatabaseException {
787         Types existing = null;
788         synchronized(typesMap) {
789             existing = (Types)typesMap.get(r);
790             if(existing == null) {
791                 existing = new Types(r);
792                 existing.setPending(querySupport);
793                 typesMap.put(keyR(r), existing);
794                 size++;
795                 return existing;
796             }
797             if(existing.requiresComputation()) {
798                 existing.setPending(querySupport);
799                 return existing;
800             }
801         }
802         if(existing.isPending()) {
803           waitPending(graph, existing);
804         }
805         return existing;
806     }
807     
808     void remove(Types entry) {
809         synchronized(typesMap) {
810             typesMap.remove(entry.id);
811         }
812     }
813     
814     public static void runnerTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
815         QueryCache cache  = graph.processor.cache;
816         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
817             if (SINGLE) {
818                 Types e = cache.peekTypes(r);
819                 if (e != null && e.isReady()) {
820                     e.performFromCache(graph, procedure);
821                     return;
822                 }
823             }
824             Types.computeForEach(graph, r, null, procedure);
825             return;
826         }
827         Types entry = (Types)cache.getOrCreateTypes(graph, r);
828         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureTypes;
829         if(entry.isReady()) {
830           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
831           entry.performFromCache(graph, procedure_);
832         }
833         else {
834           assert(entry.isPending());
835           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
836           Types.computeForEach(graph, r, entry, procedure_);
837         }
838     }
839     
840     private Types peekTypes(int r) {
841         synchronized(typesMap) {
842             return (Types) typesMap.get(r);
843         }
844     }
845     
846     ChildMap getOrCreateChildMap(ReadGraphImpl graph, int r) throws DatabaseException {
847         ChildMap existing = null;
848         synchronized(childMapMap) {
849             existing = (ChildMap)childMapMap.get(r);
850             if(existing == null) {
851                 existing = new ChildMap(r);
852                 existing.setPending(querySupport);
853                 childMapMap.put(keyR(r), existing);
854                 size++;
855                 return existing;
856             }
857             if(existing.requiresComputation()) {
858                 existing.setPending(querySupport);
859                 return existing;
860             }
861         }
862         if(existing.isPending()) {
863           waitPending(graph, existing);
864         }
865         return existing;
866     }
867     
868     void remove(ChildMap entry) {
869         synchronized(childMapMap) {
870             childMapMap.remove(entry.id);
871         }
872     }
873     
874     public static void runnerChildMap(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<ObjectResourceIdMap<String>> procedure) throws DatabaseException {
875         QueryCache cache  = graph.processor.cache;
876         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
877             if (SINGLE) {
878                 ChildMap e = cache.peekChildMap(r);
879                 if (e != null && e.isReady()) {
880                     e.performFromCache(graph, procedure);
881                     return;
882                 }
883             }
884             ChildMap.computeForEach(graph, r, null, procedure);
885             return;
886         }
887         ChildMap entry = (ChildMap)cache.getOrCreateChildMap(graph, r);
888         InternalProcedure<ObjectResourceIdMap<String>> procedure_ = procedure != null ? procedure : emptyProcedureChildMap;
889         if(entry.isReady()) {
890           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
891           entry.performFromCache(graph, procedure_);
892         }
893         else {
894           assert(entry.isPending());
895           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
896           ChildMap.computeForEach(graph, r, entry, procedure_);
897         }
898     }
899     
900     private ChildMap peekChildMap(int r) {
901         synchronized(childMapMap) {
902             return (ChildMap) childMapMap.get(r);
903         }
904     }
905     
906     TypeHierarchy getOrCreateTypeHierarchy(ReadGraphImpl graph, int r) throws DatabaseException {
907         TypeHierarchy existing = null;
908         synchronized(typeHierarchyMap) {
909             existing = (TypeHierarchy)typeHierarchyMap.get(r);
910             if(existing == null) {
911                 existing = new TypeHierarchy(r);
912                 existing.setPending(querySupport);
913                 typeHierarchyMap.put(keyR(r), existing);
914                 size++;
915                 return existing;
916             }
917             if(existing.requiresComputation()) {
918                 existing.setPending(querySupport);
919                 return existing;
920             }
921         }
922         if(existing.isPending()) {
923           waitPending(graph, existing);
924         }
925         return existing;
926     }
927     
928     void remove(TypeHierarchy entry) {
929         synchronized(typeHierarchyMap) {
930             typeHierarchyMap.remove(entry.id);
931         }
932     }
933     
934     public static void runnerTypeHierarchy(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
935         QueryCache cache  = graph.processor.cache;
936         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
937             if (SINGLE) {
938                 TypeHierarchy e = cache.peekTypeHierarchy(r);
939                 if (e != null && e.isReady()) {
940                     e.performFromCache(graph, procedure);
941                     return;
942                 }
943             }
944             TypeHierarchy.computeForEach(graph, r, null, procedure);
945             return;
946         }
947         TypeHierarchy entry = (TypeHierarchy)cache.getOrCreateTypeHierarchy(graph, r);
948         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureTypeHierarchy;
949         if(entry.isReady()) {
950           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
951           entry.performFromCache(graph, procedure_);
952         }
953         else {
954           assert(entry.isPending());
955           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
956           TypeHierarchy.computeForEach(graph, r, entry, procedure_);
957         }
958     }
959     
960     private TypeHierarchy peekTypeHierarchy(int r) {
961         synchronized(typeHierarchyMap) {
962             return (TypeHierarchy) typeHierarchyMap.get(r);
963         }
964     }
965     
966     SuperTypes getOrCreateSuperTypes(ReadGraphImpl graph, int r) throws DatabaseException {
967         SuperTypes existing = null;
968         synchronized(superTypesMap) {
969             existing = (SuperTypes)superTypesMap.get(r);
970             if(existing == null) {
971                 existing = new SuperTypes(r);
972                 existing.setPending(querySupport);
973                 superTypesMap.put(keyR(r), existing);
974                 size++;
975                 return existing;
976             }
977             if(existing.requiresComputation()) {
978                 existing.setPending(querySupport);
979                 return existing;
980             }
981         }
982         if(existing.isPending()) {
983           waitPending(graph, existing);
984         }
985         return existing;
986     }
987     
988     void remove(SuperTypes entry) {
989         synchronized(superTypesMap) {
990             superTypesMap.remove(entry.id);
991         }
992     }
993     
994     public static void runnerSuperTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
995         QueryCache cache  = graph.processor.cache;
996         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
997             if (SINGLE) {
998                 SuperTypes e = cache.peekSuperTypes(r);
999                 if (e != null && e.isReady()) {
1000                     e.performFromCache(graph, procedure);
1001                     return;
1002                 }
1003             }
1004             SuperTypes.computeForEach(graph, r, null, procedure);
1005             return;
1006         }
1007         SuperTypes entry = (SuperTypes)cache.getOrCreateSuperTypes(graph, r);
1008         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureSuperTypes;
1009         if(entry.isReady()) {
1010           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1011           entry.performFromCache(graph, procedure_);
1012         }
1013         else {
1014           assert(entry.isPending());
1015           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1016           SuperTypes.computeForEach(graph, r, entry, procedure_);
1017         }
1018     }
1019     
1020     private SuperTypes peekSuperTypes(int r) {
1021         synchronized(superTypesMap) {
1022             return (SuperTypes) superTypesMap.get(r);
1023         }
1024     }
1025     
1026     SuperRelations getOrCreateSuperRelations(ReadGraphImpl graph, int r) throws DatabaseException {
1027         SuperRelations existing = null;
1028         synchronized(superRelationsMap) {
1029             existing = (SuperRelations)superRelationsMap.get(r);
1030             if(existing == null) {
1031                 existing = new SuperRelations(r);
1032                 existing.setPending(querySupport);
1033                 superRelationsMap.put(keyR(r), existing);
1034                 size++;
1035                 return existing;
1036             }
1037             if(existing.requiresComputation()) {
1038                 existing.setPending(querySupport);
1039                 return existing;
1040             }
1041         }
1042         if(existing.isPending()) {
1043           waitPending(graph, existing);
1044         }
1045         return existing;
1046     }
1047     
1048     void remove(SuperRelations entry) {
1049         synchronized(superRelationsMap) {
1050             superRelationsMap.remove(entry.id);
1051         }
1052     }
1053     
1054     public static void runnerSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final InternalProcedure<IntSet> procedure) throws DatabaseException {
1055         QueryCache cache  = graph.processor.cache;
1056         if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) {
1057             if (SINGLE) {
1058                 SuperRelations e = cache.peekSuperRelations(r);
1059                 if (e != null && e.isReady()) {
1060                     e.performFromCache(graph, procedure);
1061                     return;
1062                 }
1063             }
1064             SuperRelations.computeForEach(graph, r, null, procedure);
1065             return;
1066         }
1067         SuperRelations entry = (SuperRelations)cache.getOrCreateSuperRelations(graph, r);
1068         InternalProcedure<IntSet> procedure_ = procedure != null ? procedure : emptyProcedureSuperRelations;
1069         if(entry.isReady()) {
1070           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1071           entry.performFromCache(graph, procedure_);
1072         }
1073         else {
1074           assert(entry.isPending());
1075           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1076           SuperRelations.computeForEach(graph, r, entry, procedure_);
1077         }
1078     }
1079     
1080     private SuperRelations peekSuperRelations(int r) {
1081         synchronized(superRelationsMap) {
1082             return (SuperRelations) superRelationsMap.get(r);
1083         }
1084     }
1085     
1086     AssertedPredicates getOrCreateAssertedPredicates(ReadGraphImpl graph, int r) throws DatabaseException {
1087         AssertedPredicates existing = null;
1088         synchronized(assertedPredicatesMap) {
1089             existing = (AssertedPredicates)assertedPredicatesMap.get(r);
1090             if(existing == null) {
1091                 existing = new AssertedPredicates(r);
1092                 existing.setPending(querySupport);
1093                 assertedPredicatesMap.put(keyR(r), existing);
1094                 size++;
1095                 return existing;
1096             }
1097             if(existing.requiresComputation()) {
1098                 existing.setPending(querySupport);
1099                 return existing;
1100             }
1101         }
1102         if(existing.isPending()) {
1103           waitPending(graph, existing);
1104         }
1105         return existing;
1106     }
1107     
1108     void remove(AssertedPredicates entry) {
1109         synchronized(assertedPredicatesMap) {
1110             assertedPredicatesMap.remove(entry.id);
1111         }
1112     }
1113     
1114     public static void runnerAssertedPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
1115         QueryCache cache  = graph.processor.cache;
1116         AssertedPredicates entry = (AssertedPredicates)cache.getOrCreateAssertedPredicates(graph, r);
1117         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureAssertedPredicates;
1118         if(entry.isReady()) {
1119           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1120           entry.performFromCache(graph, procedure_);
1121         }
1122         else {
1123           assert(entry.isPending());
1124           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1125           entry.compute(graph, procedure_);
1126         }
1127     }
1128     
1129     private AssertedPredicates peekAssertedPredicates(int r) {
1130         synchronized(assertedPredicatesMap) {
1131             return (AssertedPredicates) assertedPredicatesMap.get(r);
1132         }
1133     }
1134     
1135     AssertedStatements getOrCreateAssertedStatements(ReadGraphImpl graph, int r1, int r2) throws DatabaseException {
1136         AssertedStatements existing = null;
1137         synchronized(assertedStatementsMap) {
1138             existing = (AssertedStatements)assertedStatementsMap.get(r1,r2);
1139             if(existing == null) {
1140                 existing = new AssertedStatements(r1,r2);
1141                 existing.setPending(querySupport);
1142                 assertedStatementsMap.put(keyR2(r1,r2), existing);
1143                 size++;
1144                 return existing;
1145             }
1146             if(existing.requiresComputation()) {
1147                 existing.setPending(querySupport);
1148                 return existing;
1149             }
1150         }
1151         if(existing.isPending()) {
1152           waitPending(graph, existing);
1153         }
1154         return existing;
1155     }
1156     
1157     void remove(AssertedStatements entry) {
1158         synchronized(assertedStatementsMap) {
1159             assertedStatementsMap.remove(entry.id);
1160         }
1161     }
1162     
1163     public static void runnerAssertedStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, final TripleIntProcedure procedure) throws DatabaseException {
1164         QueryCache cache  = graph.processor.cache;
1165         AssertedStatements entry = (AssertedStatements)cache.getOrCreateAssertedStatements(graph, r1,r2);
1166         TripleIntProcedure procedure_ = procedure != null ? procedure : emptyProcedureAssertedStatements;
1167         if(entry.isReady()) {
1168           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1169           entry.performFromCache(graph, procedure_);
1170         }
1171         else {
1172           assert(entry.isPending());
1173           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1174           entry.compute(graph, procedure_);
1175         }
1176     }
1177     
1178     private AssertedStatements peekAssertedStatements(int r1, int r2) {
1179         synchronized(assertedStatementsMap) {
1180             return (AssertedStatements) assertedStatementsMap.get(r1,r2);
1181         }
1182     }
1183     
1184     DirectSuperRelations getOrCreateDirectSuperRelations(ReadGraphImpl graph, int r) throws DatabaseException {
1185         DirectSuperRelations existing = null;
1186         synchronized(directSuperRelationsMap) {
1187             existing = (DirectSuperRelations)directSuperRelationsMap.get(r);
1188             if(existing == null) {
1189                 existing = new DirectSuperRelations(r);
1190                 existing.setPending(querySupport);
1191                 directSuperRelationsMap.put(keyR(r), existing);
1192                 size++;
1193                 return existing;
1194             }
1195             if(existing.requiresComputation()) {
1196                 existing.setPending(querySupport);
1197                 return existing;
1198             }
1199         }
1200         if(existing.isPending()) {
1201           waitPending(graph, existing);
1202         }
1203         return existing;
1204     }
1205     
1206     void remove(DirectSuperRelations entry) {
1207         synchronized(directSuperRelationsMap) {
1208             directSuperRelationsMap.remove(entry.id);
1209         }
1210     }
1211     
1212     public static void runnerDirectSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) throws DatabaseException {
1213         QueryCache cache  = graph.processor.cache;
1214         DirectSuperRelations entry = (DirectSuperRelations)cache.getOrCreateDirectSuperRelations(graph, r);
1215         IntProcedure procedure_ = procedure != null ? procedure : emptyProcedureDirectSuperRelations;
1216         if(entry.isReady()) {
1217           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1218           entry.performFromCache(graph, procedure_);
1219         }
1220         else {
1221           assert(entry.isPending());
1222           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1223           entry.compute(graph, procedure_);
1224         }
1225     }
1226     
1227     private DirectSuperRelations peekDirectSuperRelations(int r) {
1228         synchronized(directSuperRelationsMap) {
1229             return (DirectSuperRelations) directSuperRelationsMap.get(r);
1230         }
1231     }
1232     
1233     MultiReadEntry getOrCreateMultiReadEntry(ReadGraphImpl graph, MultiRead<?> r) throws DatabaseException {
1234         MultiReadEntry existing = null;
1235         synchronized(multiReadEntryMap) {
1236             existing = (MultiReadEntry)multiReadEntryMap.get(r);
1237             if(existing == null) {
1238                 existing = new MultiReadEntry(r);
1239                 existing.setPending(querySupport);
1240                 multiReadEntryMap.put(id(r), existing);
1241                 size++;
1242                 return existing;
1243             }
1244             if(existing.requiresComputation()) {
1245                 existing.setPending(querySupport);
1246                 return existing;
1247             }
1248         }
1249         if(existing.isPending()) {
1250           waitPending(graph, existing);
1251         }
1252         return existing;
1253     }
1254     
1255     void remove(MultiReadEntry entry) {
1256         synchronized(multiReadEntryMap) {
1257             multiReadEntryMap.remove(entry.id);
1258         }
1259     }
1260     
1261     public static void runnerMultiReadEntry(ReadGraphImpl graph, MultiRead<?> r, CacheEntry parent, ListenerBase listener, final SyncMultiProcedure procedure) throws DatabaseException {
1262         QueryCache cache  = graph.processor.cache;
1263         MultiReadEntry entry = (MultiReadEntry)cache.getOrCreateMultiReadEntry(graph, r);
1264         SyncMultiProcedure procedure_ = procedure != null ? procedure : emptyProcedureMultiReadEntry;
1265         if(entry.isReady()) {
1266           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1267           entry.performFromCache(graph, procedure_);
1268         }
1269         else {
1270           assert(entry.isPending());
1271           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1272           entry.compute(graph, procedure_);
1273         }
1274     }
1275     
1276     private MultiReadEntry peekMultiReadEntry(MultiRead<?> r) {
1277         synchronized(multiReadEntryMap) {
1278             return (MultiReadEntry) multiReadEntryMap.get(r);
1279         }
1280     }
1281     
1282     AsyncMultiReadEntry getOrCreateAsyncMultiReadEntry(ReadGraphImpl graph, AsyncMultiRead<?> r) throws DatabaseException {
1283         AsyncMultiReadEntry existing = null;
1284         synchronized(asyncMultiReadEntryMap) {
1285             existing = (AsyncMultiReadEntry)asyncMultiReadEntryMap.get(r);
1286             if(existing == null) {
1287                 existing = new AsyncMultiReadEntry(r);
1288                 existing.setPending(querySupport);
1289                 asyncMultiReadEntryMap.put(id(r), existing);
1290                 size++;
1291                 return existing;
1292             }
1293             if(existing.requiresComputation()) {
1294                 existing.setPending(querySupport);
1295                 return existing;
1296             }
1297         }
1298         if(existing.isPending()) {
1299           waitPending(graph, existing);
1300         }
1301         return existing;
1302     }
1303     
1304     void remove(AsyncMultiReadEntry entry) {
1305         synchronized(asyncMultiReadEntryMap) {
1306             asyncMultiReadEntryMap.remove(entry.id);
1307         }
1308     }
1309     
1310     public static void runnerAsyncMultiReadEntry(ReadGraphImpl graph, AsyncMultiRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncMultiProcedure procedure) throws DatabaseException {
1311         QueryCache cache  = graph.processor.cache;
1312         AsyncMultiReadEntry entry = (AsyncMultiReadEntry)cache.getOrCreateAsyncMultiReadEntry(graph, r);
1313         AsyncMultiProcedure procedure_ = procedure != null ? procedure : emptyProcedureAsyncMultiReadEntry;
1314         if(entry.isReady()) {
1315           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1316           entry.performFromCache(graph, procedure_);
1317         }
1318         else {
1319           assert(entry.isPending());
1320           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1321           entry.compute(graph, procedure_);
1322         }
1323     }
1324     
1325     private AsyncMultiReadEntry peekAsyncMultiReadEntry(AsyncMultiRead<?> r) {
1326         synchronized(asyncMultiReadEntryMap) {
1327             return (AsyncMultiReadEntry) asyncMultiReadEntryMap.get(r);
1328         }
1329     }
1330     
1331     ExternalReadEntry getOrCreateExternalReadEntry(ReadGraphImpl graph, ExternalRead<?> r) throws DatabaseException {
1332         ExternalReadEntry existing = null;
1333         synchronized(externalReadEntryMap) {
1334             existing = (ExternalReadEntry)externalReadEntryMap.get(r);
1335             if(existing == null) {
1336                 existing = new ExternalReadEntry(r, graph);
1337                 existing.setPending(querySupport);
1338                 externalReadEntryMap.put(id(r), existing);
1339                 size++;
1340                 return existing;
1341             }
1342             if(existing.requiresComputation()) {
1343                 existing.setPending(querySupport);
1344                 return existing;
1345             }
1346         }
1347         if(existing.isPending()) {
1348           waitPending(graph, existing);
1349         }
1350         return existing;
1351     }
1352     
1353     void remove(ExternalReadEntry entry) {
1354         synchronized(externalReadEntryMap) {
1355             externalReadEntryMap.remove(entry.id);
1356         }
1357     }
1358     
1359     public static void runnerExternalReadEntry(ReadGraphImpl graph, ExternalRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure) throws DatabaseException {
1360         QueryCache cache  = graph.processor.cache;
1361         ExternalReadEntry entry = (ExternalReadEntry)cache.getOrCreateExternalReadEntry(graph, r);
1362         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureExternalReadEntry;
1363         if(entry.isReady()) {
1364           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1365           entry.performFromCache(graph, procedure_);
1366         }
1367         else {
1368           assert(entry.isPending());
1369           graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);
1370           entry.compute(graph, procedure_);
1371         }
1372     }
1373     
1374     private ExternalReadEntry peekExternalReadEntry(ExternalRead<?> r) {
1375         synchronized(externalReadEntryMap) {
1376             return (ExternalReadEntry) externalReadEntryMap.get(r);
1377         }
1378     }
1379     
1380 }