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