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