]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java
Diagram loading concurrency problem with Sysdyn
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / QueryProcessor.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.impl.query;
13
14 import java.io.BufferedOutputStream;
15 import java.io.File;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.PrintStream;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.IdentityHashMap;
26 import java.util.Iterator;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.concurrent.Semaphore;
32 import java.util.concurrent.atomic.AtomicBoolean;
33 import java.util.concurrent.atomic.AtomicInteger;
34
35 import org.simantics.databoard.Bindings;
36 import org.simantics.db.AsyncReadGraph;
37 import org.simantics.db.DevelopmentKeys;
38 import org.simantics.db.DirectStatements;
39 import org.simantics.db.ReadGraph;
40 import org.simantics.db.RelationInfo;
41 import org.simantics.db.Resource;
42 import org.simantics.db.Session;
43 import org.simantics.db.Statement;
44 import org.simantics.db.VirtualGraph;
45 import org.simantics.db.common.procedure.adapter.AsyncMultiProcedureAdapter;
46 import org.simantics.db.common.utils.Logger;
47 import org.simantics.db.debug.ListenerReport;
48 import org.simantics.db.exception.DatabaseException;
49 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
50 import org.simantics.db.exception.NoInverseException;
51 import org.simantics.db.exception.ResourceNotFoundException;
52 import org.simantics.db.impl.DebugPolicy;
53 import org.simantics.db.impl.ResourceImpl;
54 import org.simantics.db.impl.graph.BarrierTracing;
55 import org.simantics.db.impl.graph.ReadGraphImpl;
56 import org.simantics.db.impl.graph.ReadGraphSupport;
57 import org.simantics.db.impl.graph.WriteGraphImpl;
58 import org.simantics.db.impl.procedure.IntProcedureAdapter;
59 import org.simantics.db.impl.procedure.InternalProcedure;
60 import org.simantics.db.impl.procedure.TripleIntProcedureAdapter;
61 import org.simantics.db.impl.support.ResourceSupport;
62 import org.simantics.db.procedure.AsyncMultiListener;
63 import org.simantics.db.procedure.AsyncMultiProcedure;
64 import org.simantics.db.procedure.AsyncProcedure;
65 import org.simantics.db.procedure.AsyncSetListener;
66 import org.simantics.db.procedure.ListenerBase;
67 import org.simantics.db.procedure.MultiProcedure;
68 import org.simantics.db.procedure.StatementProcedure;
69 import org.simantics.db.procedure.SyncMultiProcedure;
70 import org.simantics.db.request.AsyncMultiRead;
71 import org.simantics.db.request.ExternalRead;
72 import org.simantics.db.request.MultiRead;
73 import org.simantics.db.request.RequestFlags;
74 import org.simantics.layer0.Layer0;
75 import org.simantics.utils.DataContainer;
76 import org.simantics.utils.Development;
77 import org.simantics.utils.datastructures.Pair;
78 import org.simantics.utils.datastructures.collections.CollectionUtils;
79 import org.simantics.utils.datastructures.disposable.AbstractDisposable;
80
81 import gnu.trove.procedure.TIntProcedure;
82 import gnu.trove.procedure.TLongProcedure;
83 import gnu.trove.procedure.TObjectProcedure;
84 import gnu.trove.set.hash.THashSet;
85 import gnu.trove.set.hash.TIntHashSet;
86
87 @SuppressWarnings({"rawtypes", "unchecked"})
88 final public class QueryProcessor extends AbstractDisposable implements ReadGraphSupport {
89
90         public static int                                       indent                = 0;
91
92         
93         // Garbage collection
94         
95         public int                                              boundQueries          = 0;
96
97
98         final private int                                       functionalRelation;
99
100         final private int                                       superrelationOf;
101
102         final private int                                       instanceOf;
103
104         final private int                                       inverseOf;
105
106         final private int                                       asserts;
107
108         final private int                                       hasPredicate;
109
110         final private int                                       hasPredicateInverse;
111
112         final private int                                       hasObject;
113
114         final private int                                       inherits;
115
116         final private int                                       subrelationOf;
117
118         final private int                                       rootLibrary;
119
120         /**
121          * A cache for the root library resource. Initialized in
122          * {@link #getRootLibraryResource()}.
123          */
124         private volatile ResourceImpl                           rootLibraryResource;
125
126         final private int                                       library;
127
128         final private int                                       consistsOf;
129
130         final private int                                       hasName;
131
132         AtomicInteger                                       sleepers = new AtomicInteger(0);
133
134         private boolean                                         updating              = false;
135
136
137         private boolean                                         firingListeners       = false;
138
139         final public QueryCache                                 cache;
140         final public QuerySupport                               querySupport;
141         final public Session                                    session;
142         final public ResourceSupport                            resourceSupport;
143
144         private THashSet<ListenerEntry>                         scheduledListeners    = new THashSet<ListenerEntry>();
145
146         QueryThread[]                                   executors;
147
148 //      public ArrayList<SessionTask>[]                           queues;
149         
150         public LinkedList<SessionTask>                           freeScheduling = new LinkedList<SessionTask>();
151
152         enum ThreadState {
153
154                 INIT, RUN, SLEEP, DISPOSED
155
156         }
157
158         public ThreadState[]                                                                    threadStates;
159 //      public ReentrantLock[]                                                                  threadLocks;
160 //      public Condition[]                                                                          threadConditions;
161
162         //public ArrayList<SessionTask>[]                           ownTasks;
163
164         //public ArrayList<SessionTask>[]                           ownSyncTasks;
165
166         //ArrayList<SessionTask>[]                           delayQueues;
167         
168         final Object querySupportLock;
169         
170         public Long modificationCounter = 0L;
171
172         public void close() {
173         }
174
175         public SessionTask getOwnTask(ReadGraphImpl impl) {
176                 Set<ReadGraphImpl> ancestors = impl.ancestorSet();
177                 synchronized(querySupportLock) {
178                         int index = 0;
179                         while(index < freeScheduling.size()) {
180                                 SessionTask task = freeScheduling.get(index);
181                                 if(task.hasCommonParent(ancestors)) {
182                                         return freeScheduling.remove(index);
183                                 }
184                                 index++;
185                         }
186                 }
187                 return null;
188         }
189
190     public SessionTask getSubTask(ReadGraphImpl impl) {
191         Set<ReadGraphImpl> onlyThis = Collections.singleton(impl);
192         synchronized(querySupportLock) {
193             int index = 0;
194             while(index < freeScheduling.size()) {
195                 SessionTask task = freeScheduling.get(index);
196                 if(task.hasCommonParent(onlyThis)) {
197                     return freeScheduling.remove(index);
198                 }
199                 index++;
200             }
201         }
202         return null;
203     }
204
205         public boolean performPending(ReadGraphImpl graph) {
206                 SessionTask task = getOwnTask(graph);
207                 if(task != null) {
208                         task.run(QueryProcessor.thread.get());
209                         return true;
210                 } else {
211                         return false;
212                 }
213         }
214
215 //      final public void scheduleOwn(int caller, SessionTask request) {
216 //              ownTasks[caller].add(request);
217 //      }
218
219         final public void schedule(SessionTask request) {
220             
221                 //int performer = request.thread;
222
223 //              if(DebugPolicy.SCHEDULE)
224 //                      System.out.println("schedule " + request + " " + " -> " + performer);
225
226                 //assert(performer >= 0);
227
228                 assert(request != null);
229
230 //              if(caller == performer) {
231 //                      request.run(caller);
232 //              } else {
233                         
234 //                      if(performer == THREADS) {
235                                 
236                                 synchronized(querySupportLock) {
237
238                                         if(BarrierTracing.BOOKKEEPING) {
239                                                 Exception current = new Exception();
240                                                 Exception previous = BarrierTracing.tasks.put(request, current);
241                                                 if(previous != null) {
242                                                         previous.printStackTrace();
243                                                         current.printStackTrace();
244                                                 }
245                                         }
246                                     
247                                         freeScheduling.add(request);
248                                         
249                                         querySupportLock.notifyAll();
250
251                                 }
252
253                                 return;
254                                 
255 //                      }
256 //                      
257 //                      ReentrantLock queueLock = threadLocks[performer];
258 //                      queueLock.lock();
259 //                      queues[performer].add(request);
260 //                      // This thread could have been sleeping
261 //                      if(queues[performer].size() == 1) {
262 //                              //if(ThreadState.SLEEP == threadStates[performer]) sleepers.decrementAndGet();
263 //                              threadConditions[performer].signalAll();
264 //                      }
265 //                      queueLock.unlock();
266 //              }
267
268         }
269
270
271         final int THREADS;
272         final public int  THREAD_MASK;
273
274         final public static ThreadGroup QueryThreadGroup = new ThreadGroup("Query Thread Group");
275
276         public static abstract class SessionTask {
277
278                 public final ReadGraphImpl graph;
279                 private Set<ReadGraphImpl> ancestors;
280                 private int counter = 0;
281                 private Exception trace;
282
283                 public SessionTask(ReadGraphImpl graph) {
284                         this.graph = graph;
285                         if(graph != null) graph.asyncBarrier.inc();
286                 }
287
288                 public boolean hasCommonParent(Set<ReadGraphImpl> otherAncestors) {
289                         if(graph == null) return false;
290                         if(ancestors == null) ancestors = graph.ancestorSet();
291                         return !Collections.disjoint(ancestors, otherAncestors);
292                 }
293
294                 public abstract void run0(int thread);
295
296                 public final void run(int thread) {
297                     if(counter++ > 0) {
298                         if(BarrierTracing.BOOKKEEPING) {
299                             trace.printStackTrace();
300                             new Exception().printStackTrace();
301                         }
302                         throw new IllegalStateException("Multiple invocations of SessionTask!");
303                     }
304                     if(BarrierTracing.BOOKKEEPING) {
305                         trace = new Exception();
306                     }
307                     run0(thread);
308                     if(graph != null) graph.asyncBarrier.dec();
309                 }
310
311                 @Override
312                 public String toString() {
313                         return "SessionTask[" + graph.parent + "]";
314                 }
315
316         }
317
318         public static abstract class SessionRead extends SessionTask {
319
320                 final public Semaphore notify;
321                 final public DataContainer<Throwable> throwable; 
322
323                 public SessionRead(DataContainer<Throwable> throwable, Semaphore notify) {
324                         super(null);
325                         this.throwable = throwable;
326                         this.notify = notify;
327                 }
328
329         }
330
331         long waitingTime = 0;
332
333         static int koss = 0;
334         static int koss2 = 0;
335
336         public boolean resume(ReadGraphImpl graph) {
337                 return executors[0].runSynchronized();
338         }
339         
340         //private WeakReference<GarbageTracker> garbageTracker;
341         
342         private class GarbageTracker    {
343                 
344                 @Override
345                 protected void finalize() throws Throwable {
346                         
347 //                      System.err.println("GarbageTracker");
348 //                      
349 //                      garbageTracker = new WeakReference<GarbageTracker>(new GarbageTracker());
350                         
351                         super.finalize();
352                         
353                 }
354                 
355         }
356
357         public QueryProcessor(final int threads, QuerySupport core, Set<Thread> threadSet)
358                         throws DatabaseException {
359
360                 //garbageTracker = new WeakReference<GarbageTracker>(new GarbageTracker());
361                 
362                 THREADS = threads;
363                 THREAD_MASK = threads - 1;
364
365                 querySupport = core;
366                 cache = new QueryCache(core, threads);
367                 session = querySupport.getSession();
368                 resourceSupport = querySupport.getSupport();
369                 querySupportLock = core.getLock();
370
371                 executors = new QueryThread[THREADS];
372 //              queues = new ArrayList[THREADS];
373 //              threadLocks = new ReentrantLock[THREADS];
374 //              threadConditions = new Condition[THREADS];
375                 threadStates = new ThreadState[THREADS];
376 //              ownTasks = new ArrayList[THREADS];
377 //              ownSyncTasks = new ArrayList[THREADS];
378 //              delayQueues = new ArrayList[THREADS * THREADS];
379
380                 //        freeSchedule = new AtomicInteger(0);
381
382 //              for (int i = 0; i < THREADS * THREADS; i++) {
383 //                      delayQueues[i] = new ArrayList<SessionTask>();
384 //              }
385
386                 for (int i = 0; i < THREADS; i++) {
387
388                         //            tasks[i] = new ArrayList<Runnable>();
389 //                      ownTasks[i] = new ArrayList<SessionTask>();
390 //                      ownSyncTasks[i] = new ArrayList<SessionTask>();
391 //                      queues[i] = new ArrayList<SessionTask>();
392 //                      threadLocks[i] = new ReentrantLock();
393 //                      threadConditions[i] = threadLocks[i].newCondition();
394                         //            limits[i] = false;
395                         threadStates[i] = ThreadState.INIT;
396
397                 }
398
399                 for (int i = 0; i < THREADS; i++) {
400
401                         final int index = i;
402
403                         executors[i] = new QueryThread(session, this, index, "Query Thread " + index);
404
405                         threadSet.add(executors[i]);
406
407                 }
408
409                 // Now start threads
410                 for (int i = 0; i < THREADS; i++) {
411                         executors[i].start();
412                 }
413
414                 // Make sure that query threads are up and running
415                 while(sleepers.get() != THREADS) {
416                         try {
417                                 Thread.sleep(5);
418                         } catch (InterruptedException e) {
419                                 e.printStackTrace();
420                         }
421                 }
422
423                 rootLibrary = core.getBuiltin("http:/");
424                 boolean builtinsInstalled = rootLibrary != 0;
425
426                 if (builtinsInstalled) {
427                         functionalRelation = core.getBuiltin(Layer0.URIs.FunctionalRelation);
428                         assert (functionalRelation != 0);
429                 } else
430                         functionalRelation = 0;
431
432                 if (builtinsInstalled) {
433                         instanceOf = core.getBuiltin(Layer0.URIs.InstanceOf);
434                         assert (instanceOf != 0);
435                 } else
436                         instanceOf = 0;
437
438                 if (builtinsInstalled) {
439                         inverseOf = core.getBuiltin(Layer0.URIs.InverseOf);
440                         assert (inverseOf != 0);
441                 } else
442                         inverseOf = 0;
443
444
445                 if (builtinsInstalled) {
446                         inherits = core.getBuiltin(Layer0.URIs.Inherits);
447                         assert (inherits != 0);
448                 } else
449                         inherits = 0;
450
451                 if (builtinsInstalled) {
452                         asserts = core.getBuiltin(Layer0.URIs.Asserts);
453                         assert (asserts != 0);
454                 } else
455                         asserts = 0;
456
457                 if (builtinsInstalled) {
458                         hasPredicate = core.getBuiltin(Layer0.URIs.HasPredicate);
459                         assert (hasPredicate != 0);
460                 } else
461                         hasPredicate = 0;
462
463                 if (builtinsInstalled) {
464                         hasPredicateInverse = core.getBuiltin(Layer0.URIs.HasPredicateInverse);
465                         assert (hasPredicateInverse != 0);
466                 } else
467                         hasPredicateInverse = 0;
468
469                 if (builtinsInstalled) {
470                         hasObject = core.getBuiltin(Layer0.URIs.HasObject);
471                         assert (hasObject != 0);
472                 } else
473                         hasObject = 0;
474
475                 if (builtinsInstalled) {
476                         subrelationOf = core.getBuiltin(Layer0.URIs.SubrelationOf);
477                         assert (subrelationOf != 0);
478                 } else
479                         subrelationOf = 0;
480
481                 if (builtinsInstalled) {
482                         superrelationOf = core.getBuiltin(Layer0.URIs.SuperrelationOf);
483                         assert (superrelationOf != 0);
484                 } else
485                         superrelationOf = 0;
486
487                 if (builtinsInstalled) {
488                         library = core.getBuiltin(Layer0.URIs.Library);
489                         assert (library != 0);
490                 } else
491                         library = 0;
492
493                 if (builtinsInstalled) {
494                         consistsOf = core.getBuiltin(Layer0.URIs.ConsistsOf);
495                         assert (consistsOf != 0);
496                 } else
497                         consistsOf = 0;
498
499                 if (builtinsInstalled) {
500                         hasName = core.getBuiltin(Layer0.URIs.HasName);
501                         assert (hasName != 0);
502                 } else
503                         hasName = 0;
504
505         }
506
507         final public void releaseWrite(ReadGraphImpl graph) {
508                 performDirtyUpdates(graph);
509                 modificationCounter++;
510         }
511
512         final public int getId(final Resource r) {
513                 return querySupport.getId(r);
514         }
515
516         public QuerySupport getCore() {
517                 return querySupport;
518         }
519
520         public int getFunctionalRelation() {
521                 return functionalRelation;
522         }
523
524         public int getInherits() {
525                 return inherits;
526         }
527
528         public int getInstanceOf() {
529                 return instanceOf;
530         }
531
532         public int getInverseOf() {
533                 return inverseOf;
534         }
535
536         public int getSubrelationOf() {
537                 return subrelationOf;
538         }
539
540         public int getSuperrelationOf() {
541                 return superrelationOf;
542         }
543
544         public int getAsserts() {
545                 return asserts;
546         }
547
548         public int getHasPredicate() {
549                 return hasPredicate;
550         }
551
552         public int getHasPredicateInverse() {
553                 return hasPredicateInverse;
554         }
555
556         public int getHasObject() {
557                 return hasObject;
558         }
559
560         public int getRootLibrary() {
561                 return rootLibrary;
562         }
563
564         public Resource getRootLibraryResource() {
565                 if (rootLibraryResource == null) {
566                         // Synchronization is not needed here, it doesn't matter if multiple
567                         // threads simultaneously set rootLibraryResource once.
568                         int root = getRootLibrary();
569                         if (root == 0)
570                                 throw new UnsupportedOperationException("database is not initialized, cannot get root library resource");
571                         this.rootLibraryResource = new ResourceImpl(querySupport.getSupport(), root);
572                 }
573                 return rootLibraryResource;
574         }
575
576         public int getLibrary() {
577                 return library;
578         }
579
580         public int getConsistsOf() {
581                 return consistsOf;
582         }
583
584         public int getHasName() {
585                 return hasName;
586         }
587
588         public void forResource(ReadGraphImpl graph, final String id, CacheEntry parent, final InternalProcedure<Integer> procedure) {
589
590                 try {
591                         
592                         QueryCache.runnerURIToResource(graph, id, parent, null, new InternalProcedure<Integer>() {
593
594                                 @Override
595                                 public void execute(ReadGraphImpl graph, Integer result) throws DatabaseException {
596
597                                         if (result != null && result != 0) {
598                                                 procedure.execute(graph, result);
599                                                 return;
600                                         }
601
602                                         // Fall back to using the fixed builtins.
603 //                                      result = querySupport.getBuiltin(id);
604 //                                      if (result != 0) {
605 //                                              procedure.execute(graph, result);
606 //                                              return;
607 //                                      } 
608
609 //                                      try {
610 //                                              result = querySupport.getRandomAccessReference(id);
611 //                                      } catch (ResourceNotFoundException e) {
612 //                                              procedure.exception(graph, e);
613 //                                              return;
614 //                                      }
615
616                                         if (result != 0) {
617                                                 procedure.execute(graph, result);
618                                         } else {
619                                                 procedure.exception(graph, new ResourceNotFoundException(id));
620                                         }
621
622                                 }
623
624                                 @Override
625                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
626                                         procedure.exception(graph, t);
627                                 }
628
629                         });
630                 } catch (DatabaseException e) {
631                     
632                     try {
633                         
634                 procedure.exception(graph, e);
635                 
636             } catch (DatabaseException e1) {
637                 
638                 Logger.defaultLogError(e1);
639                 
640             }
641                     
642                 }
643
644         }
645
646         public void forBuiltin(ReadGraphImpl graph, final String id, CacheEntry parent, final InternalProcedure<Integer> procedure) throws DatabaseException {
647
648                 Integer result = querySupport.getBuiltin(id);
649                 if (result != 0) {
650                         procedure.execute(graph, result);
651                 } else {
652                         procedure.exception(graph, new ResourceNotFoundException(id));
653                 }
654
655         }
656
657         final <T> void runMultiRead(final ReadGraphImpl graph, MultiReadEntry cached, final MultiRead<T> query, final CacheEntry parent, final QueryProcessor provider, final ListenerBase listener, final SyncMultiProcedure<T> procedure) {
658
659                 try {
660                         QueryCache.runnerMultiReadEntry(graph, query, parent, listener, procedure);
661                 } catch (DatabaseException e) {
662                         throw new IllegalStateException(e);
663                 }
664
665         }
666
667         public final <T> void runAsyncMultiRead(final ReadGraphImpl graph, final AsyncMultiRead<T> query, final CacheEntry parent, final ListenerBase listener, final AsyncMultiProcedure<T> procedure) {
668
669                 
670                 try {
671                         QueryCache.runnerAsyncMultiReadEntry(graph, query, parent, listener, procedure);
672                 } catch (DatabaseException e) {
673                         throw new IllegalStateException(e);
674                 }
675
676         }
677
678         final <T> void runPrimitiveRead(ReadGraphImpl graph, ExternalReadEntry cached, final ExternalRead<T> query, final CacheEntry parent, final QueryProcessor provider, final ListenerBase listener, final AsyncProcedure<T> procedure) throws DatabaseException {
679                 QueryCache.runnerExternalReadEntry(graph, query, parent, listener, procedure);
680         }
681
682 //    @Override
683 //      public <T> T query(final ReadGraphImpl graph, final Read<T> query, final CacheEntry parent, final AsyncProcedure<T> procedure, final ListenerBase listener) throws DatabaseException {
684 //      
685 //      return QueryCache.resultReadEntry(graph, query, parent, listener, procedure);
686 //
687 //      }
688
689         public <T> void queryMultiRead(final ReadGraphImpl graph, final MultiRead<T> query, final CacheEntry parent, final ListenerBase listener, final SyncMultiProcedure<T> procedure) throws DatabaseException {
690
691                 QueryCache.runnerMultiReadEntry(graph, query, parent, listener, procedure);
692
693         }
694
695         public <T> void queryPrimitiveRead(final ReadGraphImpl graph, final ExternalRead<T> query, final CacheEntry parent, final ListenerBase listener, final AsyncProcedure<T> procedure) throws DatabaseException {
696
697                 QueryCache.runnerExternalReadEntry(graph, query, parent, listener, procedure);
698
699         }
700
701         boolean isBound(ExternalReadEntry<?> entry) {
702                 if(entry.hasParents()) return true;
703                 else if(hasListener(entry)) return true;
704                 else return false;
705         }
706
707         synchronized public ListenerEntry registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) {
708
709                 if (parent != null && !inferred) {
710                         try {
711                                 if(!child.isImmutable(graph))
712                                         child.addParent(parent);
713                         } catch (DatabaseException e) {
714                                 Logger.defaultLogError(e);
715                         }
716                         if(DebugPolicy.DEPENDENCIES) System.out.println(child + " -> " + parent);
717                 }
718
719                 if (listener != null) {
720                         return registerListener(child, listener, procedure);
721                 } else {
722                         return null;
723                 }
724
725         }
726
727         
728         static class Dummy implements InternalProcedure<Object>, IntProcedure {
729
730                 @Override
731                 public void execute(ReadGraphImpl graph, int i) {
732                 }
733
734                 @Override
735                 public void finished(ReadGraphImpl graph) {
736                 }
737
738                 @Override
739                 public void execute(ReadGraphImpl graph, Object result) {
740                 }
741
742                 @Override
743                 public void exception(ReadGraphImpl graph, Throwable throwable) {
744                 }
745                 
746         }
747         
748         private static final Dummy dummy = new Dummy();
749
750         /*
751     public <Procedure> Object performForEach2(ReadGraphImpl graph, UnaryQuery<Procedure> query, CacheEntry parent, ListenerBase listener, Procedure procedure) throws Throwable {
752
753         if (DebugPolicy.PERFORM)
754             System.out.println("PE[ " + (query.hashCode() &  THREAD_MASK) + "] " + query);
755
756         assert (!dirty);
757         assert (!collecting);
758
759         assert(query.assertNotDiscarded());
760
761         registerDependencies(graph, query, parent, listener, procedure, false);
762
763         // FRESH, REFUTED, EXCEPTED go here 
764         if (!query.isReady()) {
765
766             size++;
767             misses++;
768
769             query.computeForEach(graph, this, (Procedure)dummy, true);
770             return query.get(graph, this, null);
771
772         } else {
773
774             hits++;
775
776             return query.get(graph, this, procedure);
777
778         }
779
780     }
781         */
782         
783
784         interface QueryCollectorSupport {
785                 public CacheCollectionResult allCaches();
786                 public Collection<CacheEntry> getRootList();
787                 public int getCurrentSize();
788                 public int calculateCurrentSize();
789                 public CacheEntryBase iterate(int level);
790                 public void remove();
791                 public void setLevel(CacheEntryBase entry, int level);
792                 public boolean start(boolean flush);
793         }
794
795         interface QueryCollector {
796
797                 public void collect(int youngTarget, int allowedTimeInMs);
798
799         }
800
801         class QueryCollectorSupportImpl implements QueryCollectorSupport {
802
803                 private static final boolean DEBUG = false;
804                 private static final double ITERATION_RATIO = 0.2;
805                 
806                 private CacheCollectionResult iteration = new CacheCollectionResult();
807                 private boolean fresh = true;
808                 private boolean needDataInStart = true;
809                 
810                 QueryCollectorSupportImpl() {
811                         iteration.restart();
812                 }
813
814                 public CacheCollectionResult allCaches() {
815                         CacheCollectionResult result = new CacheCollectionResult();
816                         QueryProcessor.this.allCaches(result);
817                         result.restart();
818                         return result;
819                 }
820                 
821                 public boolean start(boolean flush) {
822                         // We need new data from query maps
823                         fresh = true;
824                         if(needDataInStart || flush) {
825                                 // Last run ended after processing all queries => refresh data
826                                 restart(flush ? 0.0 : ITERATION_RATIO);
827                         } else {
828                                 // continue with previous big data
829                         }
830                         // Notify caller about iteration situation
831                         return iteration.isAtStart();
832                 }
833
834                 private void restart(double targetRatio) {
835                         
836                         needDataInStart = true;
837
838                         long start = System.nanoTime();
839                         if(fresh) {
840                                 
841                                 // We need new data from query maps
842                                 
843                                 int iterationSize = iteration.size()+1;
844                                 int diff = calculateCurrentSize()-iterationSize;
845                                 
846                                 double ratio = (double)diff / (double)iterationSize;
847                                 boolean dirty = Math.abs(ratio) >= targetRatio;
848                                 
849                                 if(dirty) {
850                                         iteration = allCaches();
851                                         if(DEBUG) {
852                                                 System.err.print("iterate: allCaches in " + 1e-9*(System.nanoTime()-start) + "s. (" + iteration.size() + ") ");
853                                                 for(int i=0;i<CacheCollectionResult.LEVELS;i++)
854                                                         System.err.print(" " + iteration.levels[i].size());
855                                                 System.err.println("");
856                                         }
857                                 } else {
858                                         iteration.restart();
859                                 }
860                                 
861                                 fresh = false;
862                                 needDataInStart = false;
863                         } else {
864                                 // We are returning here within the same GC round - reuse the cache table
865                                 iteration.restart();
866                         }
867                         
868                         return;
869                         
870                 }
871                 
872                 @Override
873                 public CacheEntryBase iterate(int level) {
874                         
875                         CacheEntryBase entry = iteration.next(level);
876                         if(entry == null) {
877                                 restart(ITERATION_RATIO);
878                                 return null;
879                         }
880                         
881                         while(entry != null && entry.isDiscarded()) {
882                                 entry = iteration.next(level);
883                         }
884                         
885                         return entry;
886                         
887                 }
888                 
889                 @Override
890                 public void remove() {
891                         iteration.remove();
892                 }
893                 
894                 @Override
895                 public void setLevel(CacheEntryBase entry, int level) {
896                         iteration.setLevel(entry, level);
897                 }
898
899                 public Collection<CacheEntry> getRootList() {
900                         return cache.getRootList();
901                 }
902
903                 @Override
904                 public int calculateCurrentSize() {
905                         return cache.calculateCurrentSize();
906                 }
907
908                 @Override
909                 public int getCurrentSize() {
910                         return cache.size;
911                 }
912
913         }
914         //    final private static int MINIMUM_SIZE = (int)(Runtime.getRuntime().maxMemory() / 600);
915
916         private QueryCollectorSupport collectorSupport = new QueryCollectorSupportImpl();
917         private QueryCollector collector = new QueryCollectorImpl(this, collectorSupport);
918
919     public int querySize() {
920         return cache.size;
921     }
922
923         public void gc(int youngTarget, int allowedTimeInMs) {
924
925                 collector.collect(youngTarget, allowedTimeInMs);
926
927         }
928
929         public ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) {
930
931                 assert (entry != null);
932
933                 if (base.isDisposed())
934                         return null;
935
936                 return addListener(entry, base, procedure);
937
938         }
939
940         private void primeListenerEntry(final ListenerEntry entry, final Object result) {
941                 entry.setLastKnown(result);
942         }
943
944         private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) {
945
946                 assert (entry != null);
947                 assert (procedure != null);
948
949                 ArrayList<ListenerEntry> list = cache.listeners.get(entry);
950                 if (list == null) {
951                         list = new ArrayList<ListenerEntry>(1);
952                         cache.listeners.put(entry, list);
953                 }
954
955                 ListenerEntry result = new ListenerEntry(entry, base, procedure);
956                 int currentIndex = list.indexOf(result);
957                 // There was already a listener
958                 if(currentIndex > -1) {
959                         ListenerEntry current = list.get(currentIndex);
960                         if(!current.base.isDisposed()) return null;
961                         list.set(currentIndex, result);
962                 } else {
963                         list.add(result);
964                 }
965
966                 if(DebugPolicy.LISTENER) {
967                         new Exception().printStackTrace();
968                         System.out.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure);
969                 }
970
971                 return result;
972
973         }
974
975         private void scheduleListener(ListenerEntry entry) {
976                 assert (entry != null);
977                 if(DebugPolicy.LISTENER) System.out.println("Scheduled " + entry.procedure);
978                 scheduledListeners.add(entry);
979         }
980
981         private void removeListener(ListenerEntry entry) {
982                 assert (entry != null);
983                 ArrayList<ListenerEntry> list = cache.listeners.get(entry.entry);
984                 if(list == null) return;
985                 boolean success = list.remove(entry);
986                 assert (success);
987                 if (list.isEmpty())
988                         cache.listeners.remove(entry.entry);
989         }
990
991         private boolean hasListener(CacheEntry entry) {
992                 if(cache.listeners.get(entry) != null) return true;
993                 return false;
994         }
995
996         boolean hasListenerAfterDisposing(CacheEntry entry) {
997                 if(cache.listeners.get(entry) != null) {
998                         ArrayList<ListenerEntry> entries = cache.listeners.get(entry);
999                         ArrayList<ListenerEntry> list = null;
1000                         for (ListenerEntry e : entries) {
1001                                 if (e.base.isDisposed()) {
1002                                         if(list == null) list = new ArrayList<ListenerEntry>();
1003                                         list.add(e);
1004                                 }
1005                         }
1006                         if(list != null) {
1007                                 for (ListenerEntry e : list) {
1008                                         entries.remove(e);
1009                                 }
1010                         }
1011                         if (entries.isEmpty()) {
1012                                 cache.listeners.remove(entry);
1013                                 return false;
1014                         }
1015                         return true;
1016                 }
1017                 return false;
1018         }
1019
1020         List<ListenerEntry> getListenerEntries(CacheEntry entry) {
1021                 hasListenerAfterDisposing(entry);
1022                 if(cache.listeners.get(entry) != null)
1023                         return cache.listeners.get(entry);
1024                 else 
1025                         return Collections.emptyList();
1026         }
1027
1028         void processListenerReport(CacheEntry<?> entry, Map<CacheEntry, Set<ListenerBase>> workarea) {
1029
1030                 if(!workarea.containsKey(entry)) {
1031
1032                         HashSet<ListenerBase> ls = new HashSet<ListenerBase>();
1033                         for(ListenerEntry e : getListenerEntries(entry))
1034                                 ls.add(e.base);
1035
1036                         workarea.put(entry, ls);
1037
1038                         for(CacheEntry parent : entry.getParents(this)) {
1039                                 processListenerReport(parent, workarea);
1040                                 ls.addAll(workarea.get(parent));
1041                         }
1042
1043                 }
1044
1045         }
1046
1047         public synchronized ListenerReport getListenerReport() throws IOException {
1048
1049                 class ListenerReportImpl implements ListenerReport {
1050
1051                         Map<CacheEntry, Set<ListenerBase>> workarea = new HashMap<CacheEntry, Set<ListenerBase>>();
1052
1053                         @Override
1054                         public void print(PrintStream b) {
1055                                 Map<ListenerBase, Integer> hist = new HashMap<ListenerBase, Integer>();
1056                                 for(Map.Entry<CacheEntry, Set<ListenerBase>> e : workarea.entrySet()) {
1057                                         for(ListenerBase l : e.getValue()) {
1058                                                 Integer i = hist.get(l);
1059                                                 hist.put(l, i != null ? i-1 : -1);
1060                                         }
1061                                 }
1062
1063                                 for(Pair<ListenerBase, Integer> p : CollectionUtils.valueSortedEntries(hist)) {
1064                                         b.print("" + -p.second + " " + p.first + "\n");
1065                                 }
1066
1067                                 b.flush();
1068                         }
1069
1070                 }
1071
1072                 ListenerReportImpl result = new ListenerReportImpl();
1073
1074                 Collection<CacheEntryBase> all = allCaches(new CacheCollectionResult()).toCollection();
1075                 for(CacheEntryBase entry : all) {
1076                         hasListenerAfterDisposing(entry);
1077                 }
1078                 for(CacheEntryBase entry : all) {
1079                         processListenerReport(entry, result.workarea);
1080                 }
1081
1082                 return result;
1083
1084         }
1085
1086         public synchronized String reportListeners(File file) throws IOException {
1087
1088                 if (!isAlive())
1089                         return "Disposed!";
1090
1091                 PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
1092                 ListenerReport report = getListenerReport();
1093                 report.print(b);
1094
1095                 return "Done reporting listeners.";
1096
1097         }
1098
1099         void processParentReport(CacheEntry entry, Map<CacheEntry, Set<CacheEntry>> workarea) {
1100
1101                 if(entry.isDiscarded()) return;
1102                 if(workarea.containsKey(entry)) return;
1103                 
1104                 Iterable<CacheEntry> parents = entry.getParents(this);
1105                 HashSet<CacheEntry> ps = new HashSet<CacheEntry>();
1106                 for(CacheEntry e : parents) {
1107                         if(e.isDiscarded()) continue;
1108                         ps.add(e);
1109                         processParentReport(e, workarea);
1110                 }
1111                 workarea.put(entry, ps);
1112
1113         }
1114
1115         public synchronized String reportQueryActivity(File file) throws IOException {
1116                 
1117                 System.err.println("reportQueries " + file.getAbsolutePath());
1118
1119                 if (!isAlive())
1120                         return "Disposed!";
1121
1122                 PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
1123
1124                 List<Pair<String,Integer>> entries = CollectionUtils.valueSortedEntries(Development.histogram);
1125                 Collections.reverse(entries);
1126                 
1127                 for(Pair<String,Integer> entry : entries) {
1128                         b.println(entry.first + ": " + entry.second);
1129                 }
1130
1131                 b.close();
1132                 
1133                 Development.histogram.clear();
1134
1135                 return "OK";
1136
1137         }
1138         
1139         public synchronized String reportQueries(File file) throws IOException {
1140
1141                 System.err.println("reportQueries " + file.getAbsolutePath());
1142
1143                 if (!isAlive())
1144                         return "Disposed!";
1145
1146                 PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
1147
1148                 long start = System.nanoTime();
1149
1150 //              ArrayList<CacheEntry> all = ;
1151                 
1152                 Map<CacheEntry, Set<CacheEntry>> workarea = new HashMap<CacheEntry, Set<CacheEntry>>();
1153                 Collection<CacheEntryBase> caches = allCaches(new CacheCollectionResult()).toCollection();
1154                 for(CacheEntryBase entry : caches) {
1155                         processParentReport(entry, workarea);
1156                 }
1157                 
1158                 //        for(CacheEntry e : all) System.err.println("entry: " + e);
1159
1160                 long duration = System.nanoTime() - start;
1161                 System.err.println("Query root set in " + 1e-9*duration + "s.");
1162
1163                 start = System.nanoTime();
1164
1165                 HashMap<CacheEntry, Integer> flagMap = new HashMap<CacheEntry, Integer>(); 
1166
1167                 int listeners = 0;
1168
1169                 for(CacheEntry entry : workarea.keySet()) {
1170                         boolean listener = hasListenerAfterDisposing(entry);
1171                         boolean hasParents = entry.getParents(this).iterator().hasNext();
1172                         if(listener) {
1173                                 // Bound
1174                                 flagMap.put(entry, 0);
1175                         } else if (!hasParents) {
1176                                 // Unbound
1177                                 flagMap.put(entry, 1);
1178                         } else {
1179                                 // Unknown
1180                                 flagMap.put(entry, 2);
1181                         }
1182                         //              // Write leaf bit
1183                         //              entry.flags |= 4;
1184                 }
1185
1186                 boolean done = true;
1187                 int loops = 0;
1188
1189                 do {
1190
1191                         done = true;
1192
1193                         long start2 = System.nanoTime();
1194
1195                         int boundCounter = 0;
1196                         int unboundCounter = 0;
1197                         int unknownCounter = 0;
1198
1199                         for(CacheEntry<?> entry : workarea.keySet()) {
1200
1201                                 //System.err.println("process " + entry);
1202
1203                                 int flags = flagMap.get(entry);
1204                                 int bindStatus = flags & 3;
1205
1206                                 if(bindStatus == 0) boundCounter++;
1207                                 else if(bindStatus == 1) unboundCounter++;
1208                                 else if(bindStatus == 2) unknownCounter++;
1209
1210                                 if(bindStatus < 2) continue;
1211
1212                                 int newStatus = 1;
1213                                 for(CacheEntry parent : entry.getParents(this)) {
1214
1215                                         if(parent.isDiscarded()) flagMap.put(parent, 1);
1216
1217                                         int flags2 = flagMap.get(parent);
1218                                         int bindStatus2 = flags2 & 3;
1219                                         // Parent is bound => child is bound
1220                                         if(bindStatus2 == 0) {
1221                                                 newStatus = 0;
1222                                                 break;
1223                                         }
1224                                         // Parent is unknown => child is unknown
1225                                         else if (bindStatus2 == 2) {
1226                                                 newStatus = 2;
1227                                                 done = false;
1228                                                 break;
1229                                         }
1230                                 }
1231
1232                                 flagMap.put(entry, newStatus);
1233
1234                         }
1235
1236                         duration = System.nanoTime() - start2;
1237                         System.err.println("Query analysis pass (" + boundCounter + "/" + unboundCounter + "/" + unknownCounter + ") in "+ 1e-9*duration + "s.");
1238                         b.println("Query analysis pass (" + boundCounter + "/" + unboundCounter + "/" + unknownCounter + ") in "+ 1e-9*duration + "s.");
1239
1240                 } while(!done && loops++ < 20);
1241
1242                 if(loops >= 20) {
1243
1244                         for(CacheEntry entry : workarea.keySet()) {
1245
1246                                 int bindStatus = flagMap.get(entry);
1247                                 if(bindStatus == 2) System.err.println("Undefined bind status for " + entry);
1248
1249                         }
1250
1251                 }
1252
1253                 duration = System.nanoTime() - start;
1254                 System.err.println("Query analysis in " + 1e-9*duration + "s.");
1255
1256                 Map<Class<?>, Integer> counts = new HashMap<Class<?>, Integer>();
1257
1258                 for(CacheEntry entry : workarea.keySet()) {
1259                         Class<?> clazz = entry.getClass();
1260                         if(entry instanceof ReadEntry) clazz = ((ReadEntry)entry).request.getClass(); 
1261                         else if(entry instanceof MultiReadEntry) clazz = ((MultiReadEntry)entry).request.getClass(); 
1262                         else if(entry instanceof AsyncReadEntry) clazz = ((AsyncReadEntry)entry).request.getClass(); 
1263                         else if(entry instanceof AsyncMultiReadEntry) clazz = ((AsyncMultiReadEntry)entry).request.getClass(); 
1264                         else if(entry instanceof ExternalReadEntry) clazz = ((ExternalReadEntry)entry).request.getClass(); 
1265                         Integer c = counts.get(clazz);
1266                         if(c == null) counts.put(clazz, -1);
1267                         else counts.put(clazz, c-1);
1268                 }
1269
1270                 b.print("// Simantics DB client query report file\n");
1271                 b.print("// This file contains the following information\n");
1272                 b.print("// -The amount of cached query instances per query class\n");
1273                 b.print("// -The sizes of retained child sets\n");
1274                 b.print("// -List of parents for each query (search for 'P <query name>')\n");
1275                 b.print("//  -Followed by status, where\n");
1276                 b.print("//   -0=bound\n");
1277                 b.print("//   -1=free\n");
1278                 b.print("//   -2=unknown\n");
1279                 b.print("//   -L=has listener\n");
1280                 b.print("// -List of children for each query (search for 'C <query name>')\n");
1281
1282                 b.print("----------------------------------------\n");
1283
1284                 b.print("// Queries by class\n");
1285                 for(Pair<Class<?>, Integer> p : CollectionUtils.valueSortedEntries(counts)) {
1286                         b.print(-p.second + " " + p.first.getName() + "\n");
1287                 }
1288
1289                 Map<CacheEntry, Integer> hist = new HashMap<CacheEntry, Integer>();
1290                 for(CacheEntry e : workarea.keySet())
1291                         hist.put(e, -1);
1292                 
1293                 boolean changed = true;
1294                 int iter = 0;
1295                 while(changed && iter++<50) {
1296                         
1297                         changed = false;
1298                         
1299                         Map<CacheEntry, Integer> newHist = new HashMap<CacheEntry, Integer>();
1300                         for(CacheEntry e : workarea.keySet())
1301                                 newHist.put(e, -1);
1302
1303                         for(Map.Entry<CacheEntry, Set<CacheEntry>> e : workarea.entrySet()) {
1304                                 Integer c = hist.get(e.getKey());
1305                                 for(CacheEntry p : e.getValue()) {
1306                                         Integer i = newHist.get(p);
1307                                         newHist.put(p, i+c);
1308                                 }
1309                         }
1310                         for(CacheEntry e : workarea.keySet()) {
1311                                 Integer value = newHist.get(e);
1312                                 Integer old = hist.get(e);
1313                                 if(!value.equals(old)) {
1314                                         hist.put(e, value);
1315 //                                      System.err.println("hist " + e + ": " + old + " => " + value);
1316                                         changed = true;
1317                                 }
1318                         }
1319                         
1320                         System.err.println("Retained set iteration " + iter);
1321
1322                 }
1323
1324                 b.print("// Queries by retained set\n");
1325                 for(Pair<CacheEntry, Integer> p : CollectionUtils.valueSortedEntries(hist)) {
1326                         b.print("" + -p.second + " " + p.first + "\n");
1327                 }
1328
1329                 HashMap<CacheEntry, Collection<CacheEntry>> inverse = new HashMap<CacheEntry, Collection<CacheEntry>>();
1330
1331                 b.print("// Entry parent listing\n");
1332                 for(CacheEntry entry : workarea.keySet()) {
1333                         int status = flagMap.get(entry);
1334                         boolean hasListener = hasListenerAfterDisposing(entry);
1335                         b.print("Q " + entry.toString());
1336                         if(hasListener) {
1337                                 b.print(" (L" + status + ")");
1338                                 listeners++;
1339                         } else {
1340                                 b.print(" (" + status + ")");
1341                         }
1342                         b.print("\n");
1343                         for(CacheEntry parent : workarea.get(entry)) {
1344                                 Collection<CacheEntry> inv = inverse.get(parent);
1345                                 if(inv == null) {
1346                                         inv = new ArrayList<CacheEntry>();
1347                                         inverse.put(parent, inv);
1348                                 }
1349                                 inv.add(entry);
1350                                 b.print("  " + parent.toString());
1351                                 b.print("\n");
1352                         }
1353                 }
1354
1355                 b.print("// Entry child listing\n");
1356                 for(Map.Entry<CacheEntry, Collection<CacheEntry>> entry : inverse.entrySet()) {
1357                         b.print("C " + entry.getKey().toString());
1358                         b.print("\n");
1359                         for(CacheEntry child : entry.getValue()) {
1360                                 Integer h = hist.get(child);
1361                                 if(h != null) {
1362                                         b.print("  " + h);
1363                                 } else {
1364                                         b.print("  <no children>");
1365                                 }
1366                                 b.print("  " + child.toString());
1367                                 b.print("\n");
1368                         }
1369                 }
1370
1371                 b.print("#queries: " + workarea.keySet().size() + "\n");
1372                 b.print("#listeners: " + listeners + "\n");
1373
1374                 b.close();
1375
1376                 return "Dumped " + workarea.keySet().size() + " queries.";
1377
1378         }
1379
1380         class UpdateEntry {
1381
1382                 public CacheEntry caller;
1383
1384                 public CacheEntry entry;
1385
1386                 public int         indent;
1387
1388                 public UpdateEntry(CacheEntry caller, CacheEntry entry, int indent) {
1389                         this.caller = caller;
1390                         this.entry = entry;
1391                         this.indent = indent;
1392                 }
1393
1394         };
1395
1396         boolean removeQuery(CacheEntry entry) {
1397
1398                 // This entry has been removed before. No need to do anything here.
1399                 if(entry.isDiscarded()) return false;
1400
1401                 assert (!entry.isDiscarded());
1402
1403                 Query query = entry.getQuery();
1404
1405                 query.removeEntry(this);
1406
1407                 cache.updates++;
1408                 cache.size--;
1409
1410                 if((entry.getGCStatus() & CacheEntry.HAS_BEEN_BOUND) != 0)
1411                         boundQueries--;
1412                 
1413                 entry.discard();
1414
1415                 return true;
1416
1417         }
1418
1419         /**
1420          * 
1421          * @return true if this entry is being listened
1422          */
1423         private boolean updateQuery(UpdateEntry e, LinkedList<UpdateEntry> todo, IdentityHashMap<CacheEntry, CacheEntry> immediates) throws DatabaseException {
1424
1425                 assert (e != null);
1426
1427                 CacheEntry entry = e.entry;
1428
1429                 //System.err.println("updateQuery " + entry);
1430                 
1431                 /*
1432                  * If the dependency graph forms a DAG, some entries are inserted in the
1433                  * todo list many times. They only need to be processed once though.
1434                  */
1435                 if (entry.isDiscarded()) {
1436                         if (Development.DEVELOPMENT) {
1437                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1438                                         System.out.print("D");
1439                                         for (int i = 0; i < e.indent; i++)
1440                                                 System.out.print(" ");
1441                                         System.out.println(entry.getQuery());
1442                                 }
1443                         }
1444 //                      System.err.println(" => DISCARDED");
1445                         return false;
1446                 }
1447
1448                 if (entry.isRefuted()) {
1449                         if (Development.DEVELOPMENT) {
1450                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1451                                         System.out.print("R");
1452                                         for (int i = 0; i < e.indent; i++)
1453                                                 System.out.print(" ");
1454                                         System.out.println(entry.getQuery());
1455                                 }
1456                         }
1457                         return false;
1458                 }
1459
1460                 if (entry.isExcepted()) {
1461                         if (Development.DEVELOPMENT) {
1462                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1463                                         System.out.print("E");
1464                                 }
1465                         }
1466                 }
1467
1468                 if (entry.isPending()) {
1469                         if (Development.DEVELOPMENT) {
1470                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1471                                         System.out.print("P");
1472                                 }
1473                         }
1474                 }
1475
1476                 cache.updates++;
1477
1478                 if (Development.DEVELOPMENT) {
1479                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1480                                 System.out.print("U ");
1481                                 for (int i = 0; i < e.indent; i++)
1482                                         System.out.print(" ");
1483                                 System.out.print(entry.getQuery());
1484                         }
1485                 }
1486
1487                 Query query = entry.getQuery();
1488                 int type = query.type();
1489
1490                 boolean hasListener = hasListener(entry); 
1491
1492                 if (Development.DEVELOPMENT) {
1493                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1494                                 if(hasListener(entry)) {
1495                                         System.out.println(" (L)");
1496                                 } else {
1497                                         System.out.println("");
1498                                 }
1499                         }
1500                 }
1501
1502                 if(entry.isPending() || entry.isExcepted()) {
1503
1504                         // If updated
1505                         if ((type & RequestFlags.UPDATE_MASK) == RequestFlags.IMMEDIATE_UPDATE) {
1506
1507                                 immediates.put(entry, entry);
1508
1509                         } else {
1510
1511                                 if(hasListener) {
1512                                         entry.refute();
1513                                 } else {
1514                                         removeQuery(entry);
1515                                 }
1516
1517                         }
1518
1519                 } else {
1520
1521                         // If updated
1522                         if ((type & RequestFlags.UPDATE_MASK) == RequestFlags.IMMEDIATE_UPDATE) {
1523
1524                                 immediates.put(entry, entry);
1525
1526                         } else {
1527
1528                                 if(hasListener) {
1529                                         entry.refute();
1530                                 } else {
1531                                         removeQuery(entry);
1532                                 }
1533
1534                         }
1535
1536                 }
1537
1538 //              System.err.println(" => FOO " + type);
1539
1540                 if (hasListener) {
1541                         ArrayList<ListenerEntry> entries = cache.listeners.get(entry);
1542                         if(entries != null) {
1543                                 for (ListenerEntry le : entries) {
1544                                         scheduleListener(le);
1545                                 }
1546                         }
1547                 }
1548
1549                 // If invalid, update parents
1550                 if (type == RequestFlags.INVALIDATE) {
1551                         updateParents(e.indent, entry, todo);
1552                 }
1553
1554                 return hasListener;
1555
1556         }
1557
1558         private void updateParents(int indent, CacheEntry entry, LinkedList<UpdateEntry> todo) {
1559
1560                 Iterable<CacheEntry> oldParents = entry.getParents(this);
1561                 for (CacheEntry parent : oldParents) {
1562 //                      System.err.println("updateParents " + entry + " => " + parent);
1563                         if(!parent.isDiscarded())
1564                                 todo.push(new UpdateEntry(entry, parent, indent + 2));
1565                 }
1566
1567         }
1568
1569         private boolean pruneListener(ListenerEntry entry) {
1570                 if (entry.base.isDisposed()) {
1571                         removeListener(entry);
1572                         return true;
1573                 } else {
1574                         return false;
1575                 }
1576         }
1577
1578         /**
1579          * @param av1 an array (guaranteed)
1580          * @param av2 any object
1581          * @return <code>true</code> if the two arrays are equal
1582          */
1583         private final boolean arrayEquals(Object av1, Object av2) {
1584                 if (av2 == null)
1585                         return false;
1586                 Class<?> c1 = av1.getClass().getComponentType();
1587                 Class<?> c2 = av2.getClass().getComponentType();
1588                 if (c2 == null || !c1.equals(c2))
1589                         return false;
1590                 boolean p1 = c1.isPrimitive();
1591                 boolean p2 = c2.isPrimitive();
1592                 if (p1 != p2)
1593                         return false;
1594                 if (!p1)
1595                         return Arrays.equals((Object[]) av1, (Object[]) av2);
1596                 if (boolean.class.equals(c1))
1597                         return Arrays.equals((boolean[]) av1, (boolean[]) av2);
1598                 else if (byte.class.equals(c1))
1599                         return Arrays.equals((byte[]) av1, (byte[]) av2);
1600                 else if (int.class.equals(c1))
1601                         return Arrays.equals((int[]) av1, (int[]) av2);
1602                 else if (long.class.equals(c1))
1603                         return Arrays.equals((long[]) av1, (long[]) av2);
1604                 else if (float.class.equals(c1))
1605                         return Arrays.equals((float[]) av1, (float[]) av2);
1606                 else if (double.class.equals(c1))
1607                         return Arrays.equals((double[]) av1, (double[]) av2);
1608                 throw new RuntimeException("??? Contact application querySupport.");
1609         }
1610
1611
1612
1613         final private Object compareTo(ReadGraphImpl graph, final CacheEntry entry, final Object oldValue) {
1614
1615                 try {
1616
1617                         Query query = entry.getQuery();
1618
1619                         if(DebugPolicy.RECOMPUTE) System.out.println("R " + query);
1620
1621                         entry.prepareRecompute(querySupport);
1622                         
1623                         ReadGraphImpl parentGraph = graph.forRecompute(entry);
1624
1625                         query.recompute(parentGraph);
1626
1627                         if(entry.isExcepted()) return ListenerEntry.NO_VALUE;
1628
1629                         Object newValue = entry.getResult();
1630
1631                         if (ListenerEntry.NO_VALUE == oldValue) {
1632                                 if(DebugPolicy.CHANGES) {
1633                                         System.out.println("C " + query);
1634                                         System.out.println("- " + oldValue);
1635                                         System.out.println("- " + newValue);
1636                                 }
1637                                 return newValue;
1638                         }
1639
1640                         boolean changed = false;
1641
1642                         if (newValue != null) {
1643                                 if (newValue.getClass().isArray()) {
1644                                         changed = !arrayEquals(newValue, oldValue);
1645                                 } else {
1646                                         changed = !newValue.equals(oldValue);
1647                                 }
1648                         } else
1649                                 changed = (oldValue != null);
1650
1651                         if(DebugPolicy.CHANGES && changed) {
1652                                 System.out.println("C " + query);
1653                                 System.out.println("- " + oldValue);
1654                                 System.out.println("- " + newValue);
1655                         }
1656
1657                         return changed ? newValue : ListenerEntry.NOT_CHANGED;
1658
1659                 } catch (Throwable t) {
1660
1661                         Logger.defaultLogError(t);
1662                         entry.except(t);
1663                         return ListenerEntry.NO_VALUE;
1664
1665                 }
1666
1667         }
1668
1669         public boolean hasScheduledUpdates() {
1670                 return !scheduledListeners.isEmpty();
1671         }
1672
1673         public void performScheduledUpdates(WriteGraphImpl graph) {
1674
1675                 assert (!updating);
1676                 assert (!cache.collecting);
1677                 assert (!firingListeners);
1678
1679                 firingListeners = true;
1680
1681                 try {
1682
1683                         // Performing may cause further events to be scheduled.
1684                         while (!scheduledListeners.isEmpty()) {
1685
1686 //                              graph.restart();
1687 //                              graph.state.barrier.inc();
1688
1689                                 // Clone current events to make new entries possible during
1690                                 // firing.
1691                                 THashSet<ListenerEntry> entries = scheduledListeners;
1692                                 scheduledListeners = new THashSet<ListenerEntry>();
1693
1694                                 ArrayList<ListenerEntry> schedule = new ArrayList<ListenerEntry>();
1695
1696                                 for (ListenerEntry listenerEntry : entries) {
1697
1698                                         if (pruneListener(listenerEntry)) {
1699                                                 if(DebugPolicy.LISTENER) System.out.println("Pruned " + listenerEntry.procedure);
1700                                                 continue;
1701                                         }
1702
1703                                         final CacheEntry entry = listenerEntry.entry;
1704                                         assert (entry != null);
1705
1706                                         Object newValue = compareTo(graph, entry, listenerEntry.getLastKnown());
1707
1708                                         if (newValue != ListenerEntry.NOT_CHANGED) {
1709                                                 if(DebugPolicy.LISTENER)
1710                                                         System.out.println("Add to schedule " + listenerEntry.procedure + " with " + newValue);
1711                                                 schedule.add(listenerEntry);
1712                                                 listenerEntry.setLastKnown(entry.getResult());
1713                                         }
1714
1715                                 }
1716
1717                                 for(ListenerEntry listenerEntry : schedule) {
1718                                         final CacheEntry entry = listenerEntry.entry;
1719                                         if(DebugPolicy.LISTENER)
1720                                                 System.out.println("Firing " + listenerEntry.procedure);
1721                                         try {
1722                                                 if(DebugPolicy.LISTENER)
1723                                                         System.out.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry);
1724                                                 entry.performFromCache(graph, listenerEntry.procedure);
1725                                         } catch (Throwable t) {
1726                                                 t.printStackTrace();
1727                                         }
1728                                 }
1729
1730 //                              graph.state.barrier.dec();
1731 //                              graph.waitAsync(null);
1732 //                              graph.state.barrier.assertReady();
1733
1734                         }
1735
1736                 } finally {
1737                         firingListeners = false;
1738                 }
1739
1740         }
1741
1742         /**
1743          * 
1744          * @return true if this entry still has listeners
1745          */
1746         public boolean update(final ReadGraphImpl graph, final CacheEntry entry) {
1747
1748                 assert (!cache.collecting);
1749                 assert (!updating);
1750                 updating = true;
1751
1752                 boolean hadListeners = false;
1753                 boolean listenersUnknown = false;
1754
1755                 try {
1756
1757                         assert(entry != null);
1758                         LinkedList<UpdateEntry> todo = new LinkedList<UpdateEntry>();
1759                         IdentityHashMap<CacheEntry, CacheEntry> immediates = new IdentityHashMap<CacheEntry, CacheEntry>();
1760                         todo.add(new UpdateEntry(null, entry, 0));
1761
1762                         while(true) {
1763
1764                                 // Walk the tree and collect immediate updates
1765                                 while (!todo.isEmpty()) {
1766                                         UpdateEntry e = todo.pop();
1767                                         hadListeners |= updateQuery(e, todo, immediates);
1768                                 }
1769
1770                                 if(immediates.isEmpty()) break;
1771
1772                                 // Evaluate all immediate updates and collect parents to update
1773                                 for(CacheEntry immediate : immediates.values()) {
1774
1775                                         if(immediate.isDiscarded()) {
1776                                                 continue;
1777                                         }
1778
1779                                         if(immediate.isExcepted()) {
1780
1781                                                 Object newValue = compareTo(graph, immediate, ListenerEntry.NO_VALUE);
1782                                                 if (newValue != ListenerEntry.NOT_CHANGED)
1783                                                         updateParents(0, immediate, todo);
1784
1785                                         } else {
1786
1787                                                 Object oldValue = immediate.getResult();
1788                                                 Object newValue = compareTo(graph, immediate, oldValue);
1789
1790                                                 if (newValue != ListenerEntry.NOT_CHANGED) {
1791                                                         updateParents(0, immediate, todo);
1792                                                 } else {
1793                                                         // If not changed, keep the old value
1794                                                         immediate.setResult(oldValue);
1795                                                         immediate.setReady();
1796                                                         listenersUnknown = true;
1797                                                 }
1798
1799                                         }
1800
1801                                 }
1802                                 immediates.clear();
1803
1804                         }
1805
1806                 } catch (Throwable t) {
1807                         Logger.defaultLogError(t);
1808                 }
1809
1810                 assert (updating);
1811                 updating = false;
1812
1813                 return hadListeners | listenersUnknown;
1814
1815         }
1816
1817         private ObjectUpdateSet scheduledObjectUpdates = new ObjectUpdateSet();
1818         private ValueUpdateSet scheduledValueUpdates = new ValueUpdateSet();
1819         private ValueUpdateSet scheduledInvalidates = new ValueUpdateSet();
1820         // Maybe use a mutex from util.concurrent?
1821         private Object primitiveUpdateLock = new Object();
1822         private THashSet scheduledPrimitiveUpdates = new THashSet();
1823
1824         public void performDirtyUpdates(final ReadGraphImpl graph) {
1825
1826                 cache.dirty = false;
1827                 lastInvalidate = 0;
1828
1829                 if (Development.DEVELOPMENT) {
1830                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1831                                 System.err.println("== Query update ==");
1832                         }
1833                 }
1834
1835                 // Special case - one statement
1836                 if(scheduledObjectUpdates.size() == 1 && scheduledValueUpdates.size() == 0 && scheduledPrimitiveUpdates.size() == 0 && scheduledInvalidates.size() == 0) {
1837
1838                         long arg0 = scheduledObjectUpdates.getFirst();
1839
1840                         final int subject = (int)(arg0 >>> 32);
1841                         final int predicate = (int)(arg0 & 0xffffffff);
1842
1843                         for(Objects o : QueryCache.entriesObjects(QueryProcessor.this, subject)) update(graph, o);
1844                         for(DirectObjects o : QueryCache.entriesDirectObjects(QueryProcessor.this, subject)) update(graph, o);
1845                         for(Statements o : QueryCache.entriesStatements(QueryProcessor.this, subject)) update(graph, o);
1846
1847                         if(predicate == instanceOf || predicate == inherits || predicate == subrelationOf) {
1848                                 PrincipalTypes principalTypes = QueryCache.entryPrincipalTypes(QueryProcessor.this, subject);
1849                                 if(principalTypes != null) update(graph, principalTypes);
1850                                 Types types = QueryCache.entryTypes(QueryProcessor.this, subject);
1851                                 if(types != null) update(graph, types);
1852                         }
1853
1854                         if(predicate == subrelationOf) {
1855                                 SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, subject);
1856                                 if(superRelations != null) update(graph, superRelations);
1857                         }
1858
1859                         DirectPredicates dp = QueryCache.entryDirectPredicates(QueryProcessor.this, subject);
1860                         if(dp != null) update(graph, dp);
1861                         OrderedSet os = QueryCache.entryOrderedSet(QueryProcessor.this, predicate);
1862                         if(os != null) update(graph, os);
1863
1864                         scheduledObjectUpdates.clear();
1865                         return;
1866
1867                 }
1868
1869                 // Special case - one value
1870                 if(scheduledObjectUpdates.size() == 0 && scheduledValueUpdates.size() == 1 && scheduledPrimitiveUpdates.size() == 0 && scheduledInvalidates.size() == 0) {
1871
1872                         int arg0 = scheduledValueUpdates.getFirst();
1873
1874                         ValueQuery valueQuery = QueryCache.entryValueQuery(QueryProcessor.this, arg0);
1875                         if(valueQuery != null) update(graph, valueQuery);
1876
1877                         scheduledValueUpdates.clear();
1878                         return;
1879
1880                 }
1881
1882                 final TIntHashSet predicates = new TIntHashSet();
1883                 final TIntHashSet orderedSets = new TIntHashSet();
1884
1885                 THashSet primitiveUpdates;
1886                 synchronized (primitiveUpdateLock) {
1887                         primitiveUpdates = scheduledPrimitiveUpdates;
1888                         scheduledPrimitiveUpdates = new THashSet();
1889                 }
1890
1891                 primitiveUpdates.forEach(new TObjectProcedure() {
1892
1893                         @Override
1894                         public boolean execute(Object arg0) {
1895
1896                                 ExternalReadEntry query = (ExternalReadEntry)cache.externalReadEntryMap.get(arg0);
1897                                 if (query != null) {
1898                                         boolean listening = update(graph, query);
1899                                         if (!listening && !query.hasParents()) {
1900                                                 cache.externalReadEntryMap.remove(arg0);
1901                                                 query.discard();
1902                                         }
1903                                 }
1904                                 return true;
1905                         }
1906
1907                 });
1908
1909                 scheduledValueUpdates.forEach(new TIntProcedure() {
1910
1911                         @Override
1912                         public boolean execute(int arg0) {
1913                                 ValueQuery valueQuery = QueryCache.entryValueQuery(QueryProcessor.this, arg0);
1914                                 if(valueQuery != null) update(graph, valueQuery);
1915                                 return true;
1916                         }
1917
1918                 });
1919
1920                 scheduledInvalidates.forEach(new TIntProcedure() {
1921
1922                         @Override
1923                         public boolean execute(int resource) {
1924                                 
1925                                 ValueQuery valueQuery = QueryCache.entryValueQuery(QueryProcessor.this, resource);
1926                                 if(valueQuery != null) update(graph, valueQuery);
1927                                 
1928                                 PrincipalTypes principalTypes = QueryCache.entryPrincipalTypes(QueryProcessor.this, resource);
1929                                 if(principalTypes != null) update(graph, principalTypes);
1930                                 Types types = QueryCache.entryTypes(QueryProcessor.this, resource);
1931                                 if(types != null) update(graph, types);
1932
1933                                 SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, resource);
1934                                 if(superRelations != null) update(graph, superRelations);
1935
1936                                 predicates.add(resource);
1937                                 
1938                                 return true;
1939                         }
1940
1941                 });
1942
1943                 scheduledObjectUpdates.forEach(new TLongProcedure() {
1944
1945                         @Override
1946                         public boolean execute(long arg0) {
1947
1948                                 final int subject = (int)(arg0 >>> 32);
1949                                 final int predicate = (int)(arg0 & 0xffffffff);
1950
1951                                 if(predicate == instanceOf || predicate == inherits || predicate == subrelationOf) {
1952                                         PrincipalTypes principalTypes = QueryCache.entryPrincipalTypes(QueryProcessor.this, subject);
1953                                         if(principalTypes != null) update(graph, principalTypes);
1954                                         Types types = QueryCache.entryTypes(QueryProcessor.this, subject);
1955                                         if(types != null) update(graph, types);
1956                                 }
1957
1958                                 if(predicate == subrelationOf) {
1959                                         SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, subject);
1960                                         if(superRelations != null) update(graph, superRelations);
1961                                 }
1962
1963                                 predicates.add(subject);
1964                                 orderedSets.add(predicate);
1965
1966                                 return true;
1967
1968                         }
1969
1970                 });
1971
1972                 predicates.forEach(new TIntProcedure() {
1973
1974                         @Override
1975                         public boolean execute(final int subject) {
1976
1977                                 for(Objects o : QueryCache.entriesObjects(QueryProcessor.this, subject)) update(graph, o);
1978                                 for(DirectObjects o : QueryCache.entriesDirectObjects(QueryProcessor.this, subject)) update(graph, o);
1979                                 for(Statements o : QueryCache.entriesStatements(QueryProcessor.this, subject)) update(graph, o);
1980
1981                                 DirectPredicates entry = QueryCache.entryDirectPredicates(QueryProcessor.this, subject);
1982                                 if(entry != null) update(graph, entry);
1983
1984                                 return true;
1985
1986                         }
1987
1988                 });
1989
1990                 orderedSets.forEach(new TIntProcedure() {
1991
1992                         @Override
1993                         public boolean execute(int orderedSet) {
1994
1995                                 OrderedSet entry = QueryCache.entryOrderedSet(QueryProcessor.this, orderedSet);
1996                                 if(entry != null) update(graph, entry);
1997
1998                                 return true;
1999
2000                         }
2001
2002                 });
2003
2004                 //              for (Integer subject : predicates) {
2005                 //                      DirectPredicates entry = DirectPredicates.entry(QueryProcessor.this, subject);
2006                 //                      if(entry != null) update(graph, entry);
2007                 //              }
2008
2009
2010                 if (Development.DEVELOPMENT) {
2011                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2012                                 System.err.println("== Query update ends ==");
2013                         }
2014                 }
2015
2016                 scheduledValueUpdates.clear();
2017                 scheduledObjectUpdates.clear();
2018                 scheduledInvalidates.clear();
2019
2020         }
2021
2022         public void updateValue(final int resource) {
2023                 scheduledValueUpdates.add(resource);
2024                 cache.dirty = true;
2025         }
2026
2027         public void updateStatements(final int resource, final int predicate) {
2028                 scheduledObjectUpdates.add((((long)resource) << 32) + predicate);
2029                 cache.dirty = true;
2030         }
2031         
2032         private int lastInvalidate = 0;
2033         
2034         public void invalidateResource(final int resource) {
2035                 if(lastInvalidate == resource) return;
2036                 scheduledValueUpdates.add(resource);
2037                 lastInvalidate = resource;
2038                 cache.dirty = true;
2039         }
2040
2041         public void updatePrimitive(final ExternalRead primitive) {
2042
2043                 // External reads may be updated from arbitrary threads.
2044                 // Synchronize to prevent race-conditions.
2045                 synchronized (primitiveUpdateLock) {
2046                         scheduledPrimitiveUpdates.add(primitive);
2047                 }
2048                 querySupport.dirtyPrimitives();
2049
2050         }
2051
2052         @Override
2053         public synchronized String toString() {
2054                 return "QueryProvider [size = " + cache.size + ", hits = " + cache.hits + " misses = " + cache.misses + ", updates = " + cache.updates + "]";
2055         }
2056
2057         @Override
2058         protected void doDispose() {
2059
2060                 for(int index = 0; index < THREADS; index++) { 
2061                         executors[index].dispose();
2062                 }
2063
2064                 // First just wait
2065                 for(int i=0;i<100;i++) {
2066
2067                         boolean alive = false;
2068                         for(int index = 0; index < THREADS; index++) { 
2069                                 alive |= executors[index].isAlive();
2070                         }
2071                         if(!alive) return;
2072                         try {
2073                                 Thread.sleep(5);
2074                         } catch (InterruptedException e) {
2075                                 Logger.defaultLogError(e);
2076                         }
2077
2078                 }
2079
2080                 // Then start interrupting
2081                 for(int i=0;i<100;i++) {
2082
2083                         boolean alive = false;
2084                         for(int index = 0; index < THREADS; index++) { 
2085                                 alive |= executors[index].isAlive();
2086                         }
2087                         if(!alive) return;
2088                         for(int index = 0; index < THREADS; index++) {
2089                                 executors[index].interrupt();
2090                         }
2091                 }
2092
2093                 //              // Then just destroy
2094                 //              for(int index = 0; index < THREADS; index++) {
2095                 //                      executors[index].destroy();
2096                 //              }
2097
2098                 for(int index = 0; index < THREADS; index++) {
2099                         try {
2100                                 executors[index].join(5000);
2101                         } catch (InterruptedException e) {
2102                                 Logger.defaultLogError("QueryThread " + index + " will not die.", e);
2103                         }
2104                         executors[index] = null;
2105                 }
2106
2107         }
2108
2109         public int getHits() {
2110                 return cache.hits;
2111         }
2112
2113         public int getMisses() {
2114                 return cache.misses;
2115         }
2116
2117         public int getSize() {
2118                 return cache.size;
2119         }
2120
2121         public Set<Long> getReferencedClusters() {
2122                 HashSet<Long> result = new HashSet<Long>();
2123                 for (CacheEntry entry : QueryCache.entriesObjects(this)) {
2124                         Objects query = (Objects) entry.getQuery();
2125                         result.add(querySupport.getClusterId(query.r1()));
2126                 }
2127                 for (CacheEntry entry : QueryCache.entriesDirectPredicates(this)) {
2128                         DirectPredicates query = (DirectPredicates) entry.getQuery();
2129                         result.add(querySupport.getClusterId(query.id));
2130                 }
2131                 for (CacheEntry entry : cache.valueQueryMap.values()) {
2132                         ValueQuery query = (ValueQuery) entry.getQuery();
2133                         result.add(querySupport.getClusterId(query.id));
2134                 }
2135                 return result;
2136         }
2137
2138         public void assertDone() {
2139         }
2140
2141         CacheCollectionResult allCaches(CacheCollectionResult result) {
2142                 
2143                 return cache.allCaches(result);
2144
2145         }
2146
2147         public void printDiagnostics() {
2148         }
2149
2150         public void requestCluster(ReadGraphImpl graph, long clusterId, Runnable runnable) {
2151                 querySupport.requestCluster(graph, clusterId, runnable);
2152         }
2153
2154         public int clean() {
2155                 collector.collect(0, Integer.MAX_VALUE);
2156                 return cache.size;
2157         }
2158
2159         public void clean(final Collection<ExternalRead<?>> requests) {
2160                 QueryCollectorSupport collectorSupport = new QueryCollectorSupport() {
2161                         Iterator<ExternalRead<?>> iterator = requests.iterator();
2162                         @Override
2163                         public CacheCollectionResult allCaches() {
2164                                 throw new UnsupportedOperationException();
2165                         }
2166                         @Override
2167                         public CacheEntryBase iterate(int level) {
2168                                 if(iterator.hasNext()) {
2169                                         ExternalRead<?> request = iterator.next();
2170                                         ExternalReadEntry entry = cache.externalReadEntryMap.get(request);
2171                                         if (entry != null) return entry;
2172                                         else return iterate(level);
2173                                 } else {
2174                                         iterator = requests.iterator();
2175                                         return null;
2176                                 }
2177                         }
2178                         @Override
2179                         public void remove() {
2180                                 throw new UnsupportedOperationException();
2181                         }
2182                         @Override
2183                         public void setLevel(CacheEntryBase entry, int level) {
2184                                 throw new UnsupportedOperationException();
2185                         }
2186                         @Override
2187                         public Collection<CacheEntry> getRootList() {
2188                                 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>(requests.size());
2189                                 for (ExternalRead<?> request : requests) {
2190                                         ExternalReadEntry entry = cache.externalReadEntryMap.get(request);
2191                                         if (entry != null)
2192                                                 result.add(entry);
2193                                 }
2194                                 return result;
2195                         }
2196                         @Override
2197                         public int getCurrentSize() {
2198                                 return cache.size;
2199                         }
2200                         @Override
2201                         public int calculateCurrentSize() {
2202                                 // This tells the collector to attempt collecting everything.
2203                                 return Integer.MAX_VALUE;
2204                         }
2205                         @Override
2206                         public boolean start(boolean flush) {
2207                                 return true;
2208                         }
2209                 };
2210                 new QueryCollectorImpl2(this, collectorSupport).collect(0, Integer.MAX_VALUE);
2211         }
2212
2213         public void scanPending() {
2214                 
2215                 cache.scanPending();
2216
2217         }
2218
2219         public ReadGraphImpl graphForVirtualRequest() {
2220                 return ReadGraphImpl.createAsync(this);
2221         }
2222
2223         
2224         private HashMap<Resource, Class<?>> builtinValues;
2225         
2226         public Class<?> getBuiltinValue(Resource r) {
2227                 if(builtinValues == null) initBuiltinValues();
2228                 return builtinValues.get(r);
2229         }
2230
2231         Exception callerException = null;
2232
2233         public interface AsyncBarrier {
2234                 public void inc(); 
2235                 public void dec();
2236                 //        public void inc(String debug); 
2237                 //        public void dec(String debug);
2238         }
2239
2240 //      final public QueryProcessor processor;
2241 //      final public QuerySupport support;
2242
2243         //    boolean disposed = false;
2244
2245         private void initBuiltinValues() {
2246
2247                 Layer0 b = getSession().peekService(Layer0.class);
2248                 if(b == null) return;
2249
2250                 builtinValues = new HashMap<Resource, Class<?>>();
2251
2252                 builtinValues.put(b.String, String.class);
2253                 builtinValues.put(b.Double, Double.class);
2254                 builtinValues.put(b.Float, Float.class);
2255                 builtinValues.put(b.Long, Long.class);
2256                 builtinValues.put(b.Integer, Integer.class);
2257                 builtinValues.put(b.Byte, Byte.class);
2258                 builtinValues.put(b.Boolean, Boolean.class);
2259
2260                 builtinValues.put(b.StringArray, String[].class);
2261                 builtinValues.put(b.DoubleArray, double[].class);
2262                 builtinValues.put(b.FloatArray, float[].class);
2263                 builtinValues.put(b.LongArray, long[].class);
2264                 builtinValues.put(b.IntegerArray, int[].class);
2265                 builtinValues.put(b.ByteArray, byte[].class);
2266                 builtinValues.put(b.BooleanArray, boolean[].class);
2267
2268         }
2269
2270 //      public ReadGraphSupportImpl(final QueryProcessor provider2) {
2271 //
2272 //              if (null == provider2) {
2273 //                      this.processor = null;
2274 //                      support = null;
2275 //                      return;
2276 //              }
2277 //              this.processor = provider2;
2278 //              support = provider2.getCore();
2279 //              initBuiltinValues();
2280 //
2281 //      }
2282
2283 //      final static public ReadGraphSupportImpl basedOn(ReadGraphSupportImpl impl) {
2284 //              return new ReadGraphSupportImpl(impl.processor);
2285 //      }
2286
2287         @Override
2288         final public Session getSession() {
2289                 return session;
2290         }
2291         
2292         final public ResourceSupport getResourceSupport() {
2293                 return resourceSupport;
2294         }
2295
2296         @Override
2297         final public void forEachPredicate(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
2298
2299         try {
2300
2301                 for(Resource predicate : getPredicates(impl, subject))
2302                     procedure.execute(impl, predicate);
2303
2304                 procedure.finished(impl);
2305
2306             } catch (Throwable e) {
2307                 procedure.exception(impl, e);
2308             }
2309
2310         }
2311
2312         @Override
2313         final public void forEachPredicate(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
2314                 
2315                 throw new UnsupportedOperationException();
2316
2317 //              assert(subject != null);
2318 //              assert(procedure != null);
2319 //
2320 //              final ListenerBase listener = getListenerBase(procedure);
2321 //
2322 //              try {
2323 //                      QueryCache.runnerPredicates(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
2324 //
2325 //                              @Override
2326 //                              public void execute(ReadGraphImpl graph, int i) {
2327 //                                      try {
2328 //                                              procedure.execute(querySupport.getResource(i));
2329 //                                      } catch (Throwable t2) {
2330 //                                              Logger.defaultLogError(t2);
2331 //                                      }
2332 //                              }
2333 //
2334 //                              @Override
2335 //                              public void finished(ReadGraphImpl graph) {
2336 //                                      try {
2337 //                                              procedure.finished();
2338 //                                      } catch (Throwable t2) {
2339 //                                              Logger.defaultLogError(t2);
2340 //                                      }
2341 ////                            impl.state.barrier.dec();
2342 //                              }
2343 //
2344 //                              @Override
2345 //                              public void exception(ReadGraphImpl graph, Throwable t) {
2346 //                                      try {
2347 //                                              procedure.exception(t);
2348 //                                      } catch (Throwable t2) {
2349 //                                              Logger.defaultLogError(t2);
2350 //                                      }
2351 ////                            impl.state.barrier.dec();
2352 //                              }
2353 //
2354 //                      });
2355 //              } catch (DatabaseException e) {
2356 //                      Logger.defaultLogError(e);
2357 //              }
2358
2359         }
2360         
2361         @Override
2362         final public IntSet getPredicates(final ReadGraphImpl impl, final Resource subject) throws Throwable {
2363                 return QueryCacheBase.resultPredicates(impl, querySupport.getId(subject), impl.parent, null); 
2364         }
2365
2366         @Override
2367         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2368                         final Resource predicate, final MultiProcedure<Statement> procedure) {
2369
2370                 assert(subject != null);
2371                 assert(predicate != null);
2372                 assert(procedure != null);
2373
2374                 final ListenerBase listener = getListenerBase(procedure);
2375
2376 //              impl.state.barrier.inc();
2377
2378                 try {
2379                         Statements.queryEach(impl, querySupport.getId(subject), querySupport.getId(predicate), this, impl.parent, listener, new TripleIntProcedureAdapter() {
2380
2381                                 @Override
2382                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
2383                                         try {
2384                                                 procedure.execute(querySupport.getStatement(s, p, o));
2385                                         } catch (Throwable t2) {
2386                                                 Logger.defaultLogError(t2);
2387                                         }
2388                                 }
2389
2390                                 @Override
2391                                 public void finished(ReadGraphImpl graph) {
2392                                         try {
2393                                                 procedure.finished();
2394                                         } catch (Throwable t2) {
2395                                                 Logger.defaultLogError(t2);
2396                                         }
2397 //                              impl.state.barrier.dec();
2398                                 }
2399
2400                                 @Override
2401                                 public void exception(ReadGraphImpl graph, Throwable t) {
2402                                         try {
2403                                                 procedure.exception(t);
2404                                         } catch (Throwable t2) {
2405                                                 Logger.defaultLogError(t2);
2406                                         }
2407 //                              impl.state.barrier.dec();
2408                                 }
2409
2410                         });
2411                 } catch (DatabaseException e) {
2412                         Logger.defaultLogError(e);
2413                 }
2414
2415         }
2416
2417         @Override
2418         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2419                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
2420
2421                 assert(subject != null);
2422                 assert(predicate != null);
2423                 assert(procedure != null);
2424
2425                 final ListenerBase listener = getListenerBase(procedure);
2426
2427                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
2428
2429                         boolean first = true;
2430
2431                         @Override
2432                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
2433                                 try {
2434                                         if(first) {
2435                                                 procedure.execute(graph, querySupport.getStatement(s, p, o));
2436                                         } else {
2437                                                 procedure.execute(impl.newRestart(graph), querySupport.getStatement(s, p, o));
2438                                         }
2439                                 } catch (Throwable t2) {
2440                                         Logger.defaultLogError(t2);
2441                                 }
2442                         }
2443
2444                         @Override
2445                         public void finished(ReadGraphImpl graph) {
2446
2447                                 try {
2448                                         if(first) {
2449                                                 first = false;
2450                                                 procedure.finished(graph);
2451 //                                              impl.state.barrier.dec(this);
2452                                         } else {
2453                                                 procedure.finished(impl.newRestart(graph));
2454                                         }
2455                                 } catch (Throwable t2) {
2456                                         Logger.defaultLogError(t2);
2457                                 }
2458
2459                         }
2460
2461                         @Override
2462                         public void exception(ReadGraphImpl graph, Throwable t) {
2463
2464                                 try {
2465                                         if(first) {
2466                                                 first = false;
2467                                                 procedure.exception(graph, t);
2468 //                                              impl.state.barrier.dec(this);
2469                                         } else {
2470                                                 procedure.exception(impl.newRestart(graph), t);
2471                                         }
2472                                 } catch (Throwable t2) {
2473                                         Logger.defaultLogError(t2);
2474                                 }
2475
2476                         }
2477
2478                 };
2479
2480                 int sId = querySupport.getId(subject);
2481                 int pId = querySupport.getId(predicate);
2482
2483 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
2484 //              else impl.state.barrier.inc(null, null);
2485
2486                 try {
2487                         Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
2488                 } catch (DatabaseException e) {
2489                         Logger.defaultLogError(e);
2490                 }
2491
2492         }
2493
2494         @Override
2495         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2496                         final Resource predicate, final StatementProcedure procedure) {
2497
2498                 assert(subject != null);
2499                 assert(predicate != null);
2500                 assert(procedure != null);
2501
2502                 final ListenerBase listener = getListenerBase(procedure);
2503
2504                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
2505
2506                         boolean first = true;
2507
2508                         @Override
2509                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
2510                                 try {
2511                                         if(first) {
2512                                                 procedure.execute(graph, s, p, o);
2513                                         } else {
2514                                                 procedure.execute(impl.newRestart(graph), s, p, o);
2515                                         }
2516                                 } catch (Throwable t2) {
2517                                         Logger.defaultLogError(t2);
2518                                 }
2519                         }
2520
2521                         @Override
2522                         public void finished(ReadGraphImpl graph) {
2523
2524                                 try {
2525                                         if(first) {
2526                                                 first = false;
2527                                                 procedure.finished(graph);
2528 //                                              impl.state.barrier.dec(this);
2529                                         } else {
2530                                                 procedure.finished(impl.newRestart(graph));
2531                                         }
2532                                 } catch (Throwable t2) {
2533                                         Logger.defaultLogError(t2);
2534                                 }
2535
2536                         }
2537
2538                         @Override
2539                         public void exception(ReadGraphImpl graph, Throwable t) {
2540
2541                                 try {
2542                                         if(first) {
2543                                                 first = false;
2544                                                 procedure.exception(graph, t);
2545 //                                              impl.state.barrier.dec(this);
2546                                         } else {
2547                                                 procedure.exception(impl.newRestart(graph), t);
2548                                         }
2549                                 } catch (Throwable t2) {
2550                                         Logger.defaultLogError(t2);
2551                                 }
2552
2553                         }
2554
2555                 };
2556
2557                 int sId = querySupport.getId(subject);
2558                 int pId = querySupport.getId(predicate);
2559
2560 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
2561 //              else impl.state.barrier.inc(null, null);
2562
2563                 try {
2564                         Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
2565                 } catch (DatabaseException e) {
2566                         Logger.defaultLogError(e);
2567                 }
2568
2569         }
2570         
2571         @Override
2572         final public void forStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
2573
2574                 assert(subject != null);
2575                 assert(predicate != null);
2576                 assert(procedure != null);
2577
2578                 forEachStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
2579
2580                         private Set<Statement> current = null;
2581                         private Set<Statement> run = new HashSet<Statement>();
2582
2583                         @Override
2584                         public void execute(AsyncReadGraph graph, Statement result) {
2585
2586                                 boolean found = false;
2587
2588                                 if(current != null) {
2589
2590                                         found = current.remove(result);
2591
2592                                 }
2593
2594                                 if(!found) procedure.add(graph, result);
2595
2596                                 run.add(result);
2597
2598                         }
2599
2600                         @Override
2601                         public void finished(AsyncReadGraph graph) {
2602
2603                                 if(current != null) { 
2604                                         for(Statement r : current) procedure.remove(graph, r);
2605                                 }
2606
2607                                 current = run;
2608
2609                                 run = new HashSet<Statement>();
2610
2611                         }
2612
2613                         @Override
2614                         public void exception(AsyncReadGraph graph, Throwable t) {
2615                                 procedure.exception(graph, t);
2616                         }
2617
2618                         @Override
2619                         public boolean isDisposed() {
2620                                 return procedure.isDisposed();
2621                         }
2622
2623                 });
2624
2625         }
2626
2627         @Override
2628         final public void forEachAssertedStatement(final ReadGraphImpl impl, final Resource subject,
2629                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
2630
2631                 assert(subject != null);
2632                 assert(predicate != null);
2633                 assert(procedure != null);
2634
2635                 final ListenerBase listener = getListenerBase(procedure);
2636
2637 //              impl.state.barrier.inc();
2638
2639                 try {
2640                         QueryCache.runnerAssertedStatements(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new TripleIntProcedureAdapter() {
2641
2642                                 @Override
2643                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
2644                                         try {
2645                                                 procedure.execute(graph, querySupport.getStatement(s, p, o));
2646                                         } catch (Throwable t2) {
2647                                                 Logger.defaultLogError(t2);
2648                                         }
2649                                 }
2650
2651                                 @Override
2652                                 public void finished(ReadGraphImpl graph) {
2653                                         try {
2654                                                 procedure.finished(graph);
2655                                         } catch (Throwable t2) {
2656                                                 Logger.defaultLogError(t2);
2657                                         }
2658 //                              impl.state.barrier.dec();
2659                                 }
2660
2661                                 @Override
2662                                 public void exception(ReadGraphImpl graph, Throwable t) {
2663                                         try {
2664                                                 procedure.exception(graph, t);
2665                                         } catch (Throwable t2) {
2666                                                 Logger.defaultLogError(t2);
2667                                         }
2668 //                              impl.state.barrier.dec();
2669                                 }
2670
2671                         });
2672                 } catch (DatabaseException e) {
2673                         Logger.defaultLogError(e);
2674                 }
2675
2676         }
2677
2678         private static ListenerBase getListenerBase(Object procedure) {
2679                 if(procedure instanceof ListenerBase) return (ListenerBase)procedure;
2680                 else return null;
2681         }
2682
2683         @Override
2684         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final MultiProcedure<Resource> procedure) {
2685
2686                 assert(subject != null);
2687                 assert(predicate != null);
2688                 assert(procedure != null);
2689
2690                 final ListenerBase listener = getListenerBase(procedure);
2691
2692 //              impl.state.barrier.inc();
2693
2694                 try {
2695                         QueryCache.runnerObjects(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new IntProcedure() {
2696
2697                                 @Override
2698                                 public void execute(ReadGraphImpl graph, int i) {
2699                                         try {
2700                                                 procedure.execute(querySupport.getResource(i));
2701                                         } catch (Throwable t2) {
2702                                                 Logger.defaultLogError(t2);
2703                                         }
2704                                 }
2705
2706                                 @Override
2707                                 public void finished(ReadGraphImpl graph) {
2708                                         try {
2709                                                 procedure.finished();
2710                                         } catch (Throwable t2) {
2711                                                 Logger.defaultLogError(t2);
2712                                         }
2713 //                              impl.state.barrier.dec();
2714                                 }
2715
2716                                 @Override
2717                                 public void exception(ReadGraphImpl graph, Throwable t) {
2718                                         System.out.println("forEachObject exception " + t);
2719                                         try {
2720                                                 procedure.exception(t);
2721                                         } catch (Throwable t2) {
2722                                                 Logger.defaultLogError(t2);
2723                                         }
2724 //                              impl.state.barrier.dec();
2725                                 }
2726
2727                         });
2728                 } catch (DatabaseException e) {
2729                         Logger.defaultLogError(e);
2730                 }
2731
2732         }
2733
2734         @Override
2735         final public void forEachDirectPredicate(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
2736
2737                 assert(subject != null);
2738                 assert(procedure != null);
2739
2740                 final ListenerBase listener = getListenerBase(procedure);
2741
2742                 int sId = querySupport.getId(subject);
2743
2744                 try {
2745                         QueryCache.runnerDirectPredicates(impl, sId, impl.parent, listener, new InternalProcedure<IntSet>() {
2746
2747                                 @Override
2748                                 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
2749                                         procedure.execute(graph, result);
2750                                 }
2751
2752                                 @Override
2753                                 public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
2754                                         procedure.exception(graph, throwable);
2755                                 }
2756                                 
2757                         });
2758                 } catch (DatabaseException e) {
2759                         Logger.defaultLogError(e);
2760                 }
2761
2762         }
2763
2764         final public DirectStatements getDirectStatements(final ReadGraphImpl impl, final Resource subject, final boolean ignoreVirtual) {
2765
2766 //              assert(subject != null);
2767 //              assert(procedure != null);
2768 //
2769 //              final ListenerBase listener = getListenerBase(procedure);
2770 //
2771 //              org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
2772                 
2773                 return querySupport.getStatements(impl, querySupport.getId(subject), this, ignoreVirtual);
2774
2775         }
2776
2777 //      @Override
2778 //      final public void forEachDirectStatement(final ReadGraphImpl impl, final Resource subject, final SyncProcedure<DirectStatements> procedure, boolean ignoreVirtual) {
2779 //
2780 //              assert(subject != null);
2781 //              assert(procedure != null);
2782 //
2783 //              final ListenerBase listener = getListenerBase(procedure);
2784 //
2785 //              org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure, ignoreVirtual);
2786 //
2787 //      }
2788         
2789         private static final Resource INVALID_RESOURCE = new ResourceImpl(null, Integer.MIN_VALUE);
2790
2791         @Override
2792         final public void forPossibleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Resource> procedure) {
2793
2794                 forEachObject(impl, subject, predicate, new AsyncMultiProcedure<Resource>() {
2795
2796                         private Resource single = null;
2797
2798                         @Override
2799                         public synchronized void execute(AsyncReadGraph graph, Resource result) {
2800                                 if(single == null) {
2801                                         single = result;
2802                                 } else {
2803                                         single = INVALID_RESOURCE;
2804                                 }
2805                         }
2806
2807                         @Override
2808                         public synchronized void finished(AsyncReadGraph graph) {
2809                                 if(single == null || single == INVALID_RESOURCE) procedure.execute(graph, null);
2810                                 else procedure.execute(graph, single);
2811                         }
2812
2813                         @Override
2814                         public synchronized void exception(AsyncReadGraph graph, Throwable throwable) {
2815                                 procedure.exception(graph, throwable);
2816                         }
2817
2818                 });
2819
2820         }
2821
2822         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final ListenerBase listener, final IntProcedure procedure) {
2823                 
2824                 final int sId = querySupport.getId(subject);
2825                 final int pId = querySupport.getId(predicate);
2826
2827                 try {
2828                         QueryCache.runnerObjects(impl, sId, pId, impl.parent, listener, procedure);
2829                 } catch (DatabaseException e) {
2830                         Logger.defaultLogError(e);
2831                 }
2832                 
2833         }
2834         
2835         static class Runner2Procedure implements IntProcedure {
2836             
2837             public int single = 0;
2838             public Throwable t = null;
2839
2840             public void clear() {
2841                 single = 0;
2842                 t = null;
2843             }
2844             
2845         @Override
2846         public void execute(ReadGraphImpl graph, int i) {
2847             if(single == 0) single = i;
2848             else single = -1;
2849         }
2850
2851         @Override
2852         public void finished(ReadGraphImpl graph) {
2853             if(single == -1) single = 0;
2854         }
2855
2856         @Override
2857         public void exception(ReadGraphImpl graph, Throwable throwable) {
2858             single = 0;
2859             this.t = throwable;
2860         }
2861         
2862         public int get() throws DatabaseException {
2863             if(t != null) {
2864                 if(t instanceof DatabaseException) throw (DatabaseException)t;
2865                 else throw new DatabaseException(t);
2866             }
2867             return single;
2868         }
2869             
2870         }
2871         
2872         final public int getSingleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate) throws DatabaseException {
2873                 
2874                 final int sId = querySupport.getId(subject);
2875                 final int pId = querySupport.getId(predicate);
2876
2877                 Runner2Procedure proc = new Runner2Procedure();
2878                 QueryCache.runnerObjects(impl, sId, pId, impl.parent, null, proc);
2879                 return proc.get();
2880             
2881         }
2882
2883         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
2884
2885                 assert(subject != null);
2886                 assert(predicate != null);
2887
2888                 final ListenerBase listener = getListenerBase(procedure);
2889
2890                 if(impl.parent != null || listener != null) {
2891
2892                         IntProcedure ip = new IntProcedure() {
2893
2894                                 AtomicBoolean first = new AtomicBoolean(true);
2895
2896                                 @Override
2897                                 public void execute(ReadGraphImpl graph, int i) {
2898                                         try {
2899                                                 if(first.get()) {
2900                                                         procedure.execute(impl, querySupport.getResource(i));
2901                                                 } else {
2902                                                         procedure.execute(impl.newRestart(graph), querySupport.getResource(i));
2903                                                 }
2904                                         } catch (Throwable t2) {
2905                                                 Logger.defaultLogError(t2);
2906                                         }
2907
2908                                 }
2909
2910                                 @Override
2911                                 public void finished(ReadGraphImpl graph) {
2912                                         try {
2913                                                 if(first.compareAndSet(true, false)) {
2914                                                         procedure.finished(impl);
2915 //                                                      impl.state.barrier.dec(this);
2916                                                 } else {
2917                                                         procedure.finished(impl.newRestart(graph));
2918                                                 }
2919                                         } catch (Throwable t2) {
2920                                                 Logger.defaultLogError(t2);
2921                                         }
2922                                 }
2923
2924                                 @Override
2925                                 public void exception(ReadGraphImpl graph, Throwable t) {
2926                                         try {
2927                                                 procedure.exception(graph, t);
2928                                         } catch (Throwable t2) {
2929                                                 Logger.defaultLogError(t2);
2930                                         }
2931 //                                      impl.state.barrier.dec(this);
2932                                 }
2933
2934                                 @Override
2935                                 public String toString() {
2936                                         return "forEachObject with " + procedure;
2937                                 }
2938
2939                         };
2940
2941 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Objects" + subject + "#" + predicate);
2942 //                      else impl.state.barrier.inc(null, null);
2943
2944                         forEachObject(impl, subject, predicate, listener, ip);
2945
2946                 } else {
2947
2948                         IntProcedure ip = new IntProcedure() {
2949
2950                                 @Override
2951                                 public void execute(ReadGraphImpl graph, int i) {
2952                                         procedure.execute(graph, querySupport.getResource(i));
2953                                 }
2954
2955                                 @Override
2956                                 public void finished(ReadGraphImpl graph) {
2957                                         procedure.finished(graph);
2958                                 }
2959
2960                                 @Override
2961                                 public void exception(ReadGraphImpl graph, Throwable t) {
2962                                         procedure.exception(graph, t);
2963                                 }
2964
2965                                 @Override
2966                                 public String toString() {
2967                                         return "forEachObject with " + procedure;
2968                                 }
2969
2970                         };
2971
2972                         forEachObject(impl, subject, predicate, listener, ip);
2973
2974                 }
2975
2976         }
2977
2978         @Override
2979         final public void forObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
2980
2981                 assert(subject != null);
2982                 assert(predicate != null);
2983                 assert(procedure != null);
2984
2985                 forEachObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
2986
2987                         private Set<Resource> current = null;
2988                         private Set<Resource> run = new HashSet<Resource>();
2989
2990                         @Override
2991                         public void execute(AsyncReadGraph graph, Resource result) {
2992
2993                                 boolean found = false;
2994
2995                                 if(current != null) {
2996
2997                                         found = current.remove(result);
2998
2999                                 }
3000
3001                                 if(!found) procedure.add(graph, result);
3002
3003                                 run.add(result);
3004
3005                         }
3006
3007                         @Override
3008                         public void finished(AsyncReadGraph graph) {
3009
3010                                 if(current != null) { 
3011                                         for(Resource r : current) procedure.remove(graph, r);
3012                                 }
3013
3014                                 current = run;
3015
3016                                 run = new HashSet<Resource>();
3017
3018                         }
3019
3020                         @Override
3021                         public boolean isDisposed() {
3022                                 return procedure.isDisposed();
3023                         }
3024
3025                         @Override
3026                         public void exception(AsyncReadGraph graph, Throwable t) {
3027                                 procedure.exception(graph, t);
3028                         }
3029
3030                         @Override
3031                         public String toString() {
3032                                 return "forObjectSet " + procedure;
3033                         }
3034
3035                 });
3036
3037         }
3038
3039         @Override
3040         final public void forPredicateSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
3041
3042                 assert(subject != null);
3043                 assert(procedure != null);
3044
3045                 forEachPredicate(impl, subject, new AsyncMultiListener<Resource>() {
3046
3047                         private Set<Resource> current = null;
3048                         private Set<Resource> run = new HashSet<Resource>();
3049
3050                         @Override
3051                         public void execute(AsyncReadGraph graph, Resource result) {
3052
3053                                 boolean found = false;
3054
3055                                 if(current != null) {
3056
3057                                         found = current.remove(result);
3058
3059                                 }
3060
3061                                 if(!found) procedure.add(graph, result);
3062
3063                                 run.add(result);
3064
3065                         }
3066
3067                         @Override
3068                         public void finished(AsyncReadGraph graph) {
3069
3070                                 if(current != null) { 
3071                                         for(Resource r : current) procedure.remove(graph, r);
3072                                 }
3073
3074                                 current = run;
3075
3076                                 run = new HashSet<Resource>();
3077
3078                         }
3079
3080                         @Override
3081                         public boolean isDisposed() {
3082                                 return procedure.isDisposed();
3083                         }
3084
3085                         @Override
3086                         public void exception(AsyncReadGraph graph, Throwable t) {
3087                                 procedure.exception(graph, t);
3088                         }
3089
3090                         @Override
3091                         public String toString() {
3092                                 return "forPredicateSet " + procedure;
3093                         }
3094
3095                 });
3096
3097         }
3098
3099         @Override
3100         final public void forPrincipalTypeSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
3101
3102                 assert(subject != null);
3103                 assert(procedure != null);
3104
3105                 forEachPrincipalType(impl, subject, new AsyncMultiListener<Resource>() {
3106
3107                         private Set<Resource> current = null;
3108                         private Set<Resource> run = new HashSet<Resource>();
3109
3110                         @Override
3111                         public void execute(AsyncReadGraph graph, Resource result) {
3112
3113                                 boolean found = false;
3114
3115                                 if(current != null) {
3116
3117                                         found = current.remove(result);
3118
3119                                 }
3120
3121                                 if(!found) procedure.add(graph, result);
3122
3123                                 run.add(result);
3124
3125                         }
3126
3127                         @Override
3128                         public void finished(AsyncReadGraph graph) {
3129
3130                                 if(current != null) { 
3131                                         for(Resource r : current) procedure.remove(graph, r);
3132                                 }
3133
3134                                 current = run;
3135
3136                                 run = new HashSet<Resource>();
3137
3138                         }
3139
3140                         @Override
3141                         public boolean isDisposed() {
3142                                 return procedure.isDisposed();
3143                         }
3144
3145                         @Override
3146                         public void exception(AsyncReadGraph graph, Throwable t) {
3147                                 procedure.exception(graph, t);
3148                         }
3149
3150                         @Override
3151                         public String toString() {
3152                                 return "forPrincipalTypeSet " + procedure;
3153                         }
3154
3155                 });
3156
3157         }
3158
3159         @Override
3160         final public void forAssertedObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
3161
3162                 assert(subject != null);
3163                 assert(predicate != null);
3164                 assert(procedure != null);
3165
3166                 forEachAssertedObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
3167
3168                         private Set<Resource> current = null;
3169                         private Set<Resource> run = new HashSet<Resource>();
3170
3171                         @Override
3172                         public void execute(AsyncReadGraph graph, Resource result) {
3173
3174                                 boolean found = false;
3175
3176                                 if(current != null) {
3177
3178                                         found = current.remove(result);
3179
3180                                 }
3181
3182                                 if(!found) procedure.add(graph, result);
3183
3184                                 run.add(result);
3185
3186                         }
3187
3188                         @Override
3189                         public void finished(AsyncReadGraph graph) {
3190
3191                                 if(current != null) { 
3192                                         for(Resource r : current) procedure.remove(graph, r);
3193                                 }
3194
3195                                 current = run;
3196
3197                                 run = new HashSet<Resource>();
3198
3199                         }
3200
3201                         @Override
3202                         public boolean isDisposed() {
3203                                 return procedure.isDisposed();
3204                         }
3205
3206                         @Override
3207                         public void exception(AsyncReadGraph graph, Throwable t) {
3208                                 procedure.exception(graph, t);
3209                         }
3210
3211                         @Override
3212                         public String toString() {
3213                                 return "forObjectSet " + procedure;
3214                         }
3215
3216                 });
3217
3218         }
3219
3220         @Override
3221         final public void forAssertedStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
3222
3223                 assert(subject != null);
3224                 assert(predicate != null);
3225                 assert(procedure != null);
3226
3227                 forEachAssertedStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
3228
3229                         private Set<Statement> current = null;
3230                         private Set<Statement> run = new HashSet<Statement>();
3231
3232                         @Override
3233                         public void execute(AsyncReadGraph graph, Statement result) {
3234
3235                                 boolean found = false;
3236
3237                                 if(current != null) {
3238
3239                                         found = current.remove(result);
3240
3241                                 }
3242
3243                                 if(!found) procedure.add(graph, result);
3244
3245                                 run.add(result);
3246
3247                         }
3248
3249                         @Override
3250                         public void finished(AsyncReadGraph graph) {
3251
3252                                 if(current != null) { 
3253                                         for(Statement s : current) procedure.remove(graph, s);
3254                                 }
3255
3256                                 current = run;
3257
3258                                 run = new HashSet<Statement>();
3259
3260                         }
3261
3262                         @Override
3263                         public boolean isDisposed() {
3264                                 return procedure.isDisposed();
3265                         }
3266
3267                         @Override
3268                         public void exception(AsyncReadGraph graph, Throwable t) {
3269                                 procedure.exception(graph, t);
3270                         }
3271
3272                         @Override
3273                         public String toString() {
3274                                 return "forStatementSet " + procedure;
3275                         }
3276
3277                 });
3278
3279         }
3280
3281         @Override
3282         final public void forEachAssertedObject(final ReadGraphImpl impl, final Resource subject,
3283                         final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
3284
3285                 assert(subject != null);
3286                 assert(predicate != null);
3287                 assert(procedure != null);
3288
3289                 final ListenerBase listener = getListenerBase(procedure);
3290
3291                 try {
3292                         QueryCache.runnerAssertedStatements(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new TripleIntProcedure() {
3293
3294                                 @Override
3295                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
3296                                         try {
3297                                                 procedure.execute(graph, querySupport.getResource(o));
3298                                         } catch (Throwable t2) {
3299                                                 Logger.defaultLogError(t2);
3300                                         }
3301                                 }
3302
3303                                 @Override
3304                                 public void finished(ReadGraphImpl graph) {
3305                                         try {               
3306                                                 procedure.finished(graph);
3307                                         } catch (Throwable t2) {
3308                                                 Logger.defaultLogError(t2);
3309                                         }
3310 //                              impl.state.barrier.dec();
3311                                 }
3312
3313                                 @Override
3314                                 public void exception(ReadGraphImpl graph, Throwable t) {
3315                                         try {
3316                                                 procedure.exception(graph, t);
3317                                         } catch (Throwable t2) {
3318                                                 Logger.defaultLogError(t2);
3319                                         }
3320 //                              impl.state.barrier.dec();
3321                                 }
3322
3323                         });
3324                 } catch (DatabaseException e) {
3325                         Logger.defaultLogError(e);
3326                 }
3327
3328         }
3329
3330         @Override
3331         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3332
3333                 assert(subject != null);
3334                 assert(procedure != null);
3335
3336                 final ListenerBase listener = getListenerBase(procedure);
3337
3338                 IntProcedure ip = new IntProcedure() {
3339
3340                         @Override
3341                         public void execute(ReadGraphImpl graph, int i) {
3342                                 try {
3343                                         procedure.execute(graph, querySupport.getResource(i));
3344                                 } catch (Throwable t2) {
3345                                         Logger.defaultLogError(t2);
3346                                 }
3347                         }
3348
3349                         @Override
3350                         public void finished(ReadGraphImpl graph) {
3351                                 try {
3352                                         procedure.finished(graph);
3353                                 } catch (Throwable t2) {
3354                                         Logger.defaultLogError(t2);
3355                                 }
3356 //                              impl.state.barrier.dec(this);
3357                         }
3358
3359                         @Override
3360                         public void exception(ReadGraphImpl graph, Throwable t) {
3361                                 try {
3362                                         procedure.exception(graph, t);
3363                                 } catch (Throwable t2) {
3364                                         Logger.defaultLogError(t2);
3365                                 }
3366 //                              impl.state.barrier.dec(this);
3367                         }
3368
3369                 };
3370
3371                 int sId = querySupport.getId(subject);
3372
3373 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#PrincipalTypes#" + sId);
3374 //              else impl.state.barrier.inc(null, null);
3375
3376                 try {
3377                         QueryCache.runnerPrincipalTypes(impl, sId, impl.parent, listener, ip);
3378                 } catch (DatabaseException e) {
3379                         Logger.defaultLogError(e);
3380                 }
3381
3382         }
3383
3384         @Override
3385         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
3386
3387                 assert(subject != null);
3388                 assert(procedure != null);
3389
3390                 final ListenerBase listener = getListenerBase(procedure);
3391
3392 //              impl.state.barrier.inc();
3393
3394                 try {
3395                         QueryCache.runnerPrincipalTypes(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
3396
3397                                 @Override
3398                                 public void execute(ReadGraphImpl graph, int i) {
3399                                         try {
3400                                                 procedure.execute(querySupport.getResource(i));
3401                                         } catch (Throwable t2) {
3402                                                 Logger.defaultLogError(t2);
3403                                         }
3404                                 }
3405
3406                                 @Override
3407                                 public void finished(ReadGraphImpl graph) {
3408                                         try {
3409                                                 procedure.finished();
3410                                         } catch (Throwable t2) {
3411                                                 Logger.defaultLogError(t2);
3412                                         }
3413 //                              impl.state.barrier.dec();
3414                                 }
3415
3416                                 @Override
3417                                 public void exception(ReadGraphImpl graph, Throwable t) {
3418                                         try {
3419                                                 procedure.exception(t);
3420                                         } catch (Throwable t2) {
3421                                                 Logger.defaultLogError(t2);
3422                                         }
3423 //                              impl.state.barrier.dec();
3424                                 }
3425
3426                         });
3427                 } catch (DatabaseException e) {
3428                         Logger.defaultLogError(e);
3429                 }
3430         }
3431
3432     final public void forTypes(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3433
3434         assert(subject != null);
3435         assert(procedure != null);
3436
3437         final ListenerBase listener = getListenerBase(procedure);
3438         assert(listener == null);
3439
3440         InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
3441
3442             @Override
3443             public void execute(final ReadGraphImpl graph, IntSet set) {
3444                 procedure.execute(graph, set);
3445             }
3446
3447             @Override
3448             public void exception(ReadGraphImpl graph, Throwable t) {
3449                 procedure.exception(graph, t);
3450             }
3451
3452         };
3453
3454         int sId = querySupport.getId(subject);
3455
3456         try {
3457                         QueryCache.runnerTypes(impl, sId, impl.parent, listener, ip);
3458                 } catch (DatabaseException e) {
3459                         Logger.defaultLogError(e);
3460                 }
3461
3462     }
3463     
3464         @Override
3465         final public IntSet getTypes(final ReadGraphImpl impl, final Resource subject) throws Throwable {
3466
3467                 assert(subject != null);
3468                 
3469                 return QueryCacheBase.resultTypes(impl, querySupport.getId(subject), impl.parent, null);
3470
3471         }
3472
3473         @Override
3474         final public RelationInfo getRelationInfo(final ReadGraphImpl impl, final Resource subject) throws DatabaseException {
3475                 
3476                 assert(subject != null);
3477
3478                 return QueryCache.resultRelationInfoQuery(impl, querySupport.getId(subject), impl.parent, null);
3479
3480         }
3481
3482         @Override
3483         final public void forSupertypes(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3484
3485                 assert(subject != null);
3486                 assert(procedure != null);
3487
3488                 final ListenerBase listener = getListenerBase(procedure);
3489
3490                 try {
3491                         QueryCache.runnerSuperTypes(impl, querySupport.getId(subject), impl.parent, listener, new InternalProcedure<IntSet>() {
3492
3493                                 AtomicBoolean first = new AtomicBoolean(true);
3494
3495                                 @Override
3496                                 public void execute(final ReadGraphImpl graph, IntSet set) {
3497 //                              final HashSet<Resource> result = new HashSet<Resource>();
3498 //                              set.forEach(new TIntProcedure() {
3499 //
3500 //                                      @Override
3501 //                                      public boolean execute(int type) {
3502 //                                              result.add(querySupport.getResource(type));
3503 //                                              return true;
3504 //                                      }
3505 //
3506 //                              });
3507                                         try {
3508                                                 if(first.compareAndSet(true, false)) {
3509                                                         procedure.execute(graph, set);
3510 //                                              impl.state.barrier.dec();
3511                                                 } else {
3512                                                         procedure.execute(impl.newRestart(graph), set);
3513                                                 }
3514                                         } catch (Throwable t2) {
3515                                                 Logger.defaultLogError(t2);
3516                                         }
3517                                 }
3518
3519                                 @Override
3520                                 public void exception(ReadGraphImpl graph, Throwable t) {
3521                                         try {
3522                                                 if(first.compareAndSet(true, false)) {
3523                                                         procedure.exception(graph, t);
3524 //                                              impl.state.barrier.dec();
3525                                                 } else {
3526                                                         procedure.exception(impl.newRestart(graph), t);
3527                                                 }
3528                                         } catch (Throwable t2) {
3529                                                 Logger.defaultLogError(t2);
3530                                         }
3531                                 }
3532
3533                         });
3534                 } catch (DatabaseException e) {
3535                         Logger.defaultLogError(e);
3536                 }
3537
3538         }
3539
3540         @Override
3541         final public void forDirectSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3542
3543                 assert(subject != null);
3544                 assert(procedure != null);
3545
3546                 final ListenerBase listener = getListenerBase(procedure);
3547
3548                 IntProcedure ip = new IntProcedureAdapter() {
3549
3550                         @Override
3551                         public void execute(final ReadGraphImpl graph, int superRelation) {
3552                                 try {
3553                                         procedure.execute(graph, querySupport.getResource(superRelation));
3554                                 } catch (Throwable t2) {
3555                                         Logger.defaultLogError(t2);
3556                                 }
3557                         }
3558
3559                         @Override
3560                         public void finished(final ReadGraphImpl graph) {
3561                                 try {
3562                                         procedure.finished(graph);
3563                                 } catch (Throwable t2) {
3564                                         Logger.defaultLogError(t2);
3565                                 }
3566 //                              impl.state.barrier.dec(this);
3567                         }
3568
3569
3570                         @Override
3571                         public void exception(ReadGraphImpl graph, Throwable t) {
3572                                 try {
3573                                         procedure.exception(graph, t);
3574                                 } catch (Throwable t2) {
3575                                         Logger.defaultLogError(t2);
3576                                 }
3577 //                              impl.state.barrier.dec(this);
3578                         }
3579
3580                 };
3581
3582                 int sId = querySupport.getId(subject); 
3583
3584 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectSuperRelations#" + sId);
3585 //              else impl.state.barrier.inc(null, null);
3586
3587                 try {
3588                         QueryCache.runnerDirectSuperRelations(impl, sId, impl.parent, listener, ip);
3589                 } catch (DatabaseException e) {
3590                         Logger.defaultLogError(e);
3591                 }
3592                 
3593 //              DirectSuperRelations.queryEach(impl, sId, this, impl.parent, listener, ip);
3594
3595         }
3596
3597         @Override
3598         final public void forPossibleSuperrelation(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Resource> procedure) {
3599
3600                 assert(subject != null);
3601                 assert(procedure != null);
3602
3603                 final ListenerBase listener = getListenerBase(procedure);
3604
3605 //              impl.state.barrier.inc();
3606
3607                 PossibleSuperRelation.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
3608
3609         }
3610
3611         @Override
3612         final public void forSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3613
3614                 assert(subject != null);
3615                 assert(procedure != null);
3616
3617                 final ListenerBase listener = getListenerBase(procedure);
3618
3619                 InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
3620
3621                         @Override
3622                         public void execute(final ReadGraphImpl graph, IntSet set) {
3623 //                              final HashSet<Resource> result = new HashSet<Resource>();
3624 //                              set.forEach(new TIntProcedure() {
3625 //
3626 //                                      @Override
3627 //                                      public boolean execute(int type) {
3628 //                                              result.add(querySupport.getResource(type));
3629 //                                              return true;
3630 //                                      }
3631 //
3632 //                              });
3633                                 try {
3634                                         procedure.execute(graph, set);
3635                                 } catch (Throwable t2) {
3636                                         Logger.defaultLogError(t2);
3637                                 }
3638 //                              impl.state.barrier.dec(this);
3639                         }
3640
3641                         @Override
3642                         public void exception(ReadGraphImpl graph, Throwable t) {
3643                                 try {
3644                                         procedure.exception(graph, t);
3645                                 } catch (Throwable t2) {
3646                                         Logger.defaultLogError(t2);
3647                                 }
3648 //                              impl.state.barrier.dec(this);
3649                         }
3650
3651                 };
3652
3653                 int sId = querySupport.getId(subject);
3654
3655 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#SuperRelations#" + sId);
3656 //              else impl.state.barrier.inc(null, null);
3657
3658                 try {
3659                         QueryCache.runnerSuperRelations(impl, sId, impl.parent, listener, ip);
3660                 } catch (DatabaseException e) {
3661                         Logger.defaultLogError(e);
3662                 }
3663
3664         }
3665
3666         final public byte[] getValue(final ReadGraphImpl impl, final Resource subject) throws DatabaseException {
3667           return getValue(impl, querySupport.getId(subject));
3668         }
3669
3670         final public byte[] getValue(final ReadGraphImpl impl, final int subject) throws DatabaseException {
3671                 return QueryCache.resultValueQuery(impl, subject, impl.parent, null); 
3672         }
3673
3674         @Override
3675         final public void forValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
3676
3677                 assert(subject != null);
3678                 assert(procedure != null);
3679
3680                 int sId = querySupport.getId(subject);
3681
3682 //              if(procedure != null) {
3683                 
3684                         final ListenerBase listener = getListenerBase(procedure);
3685
3686                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3687
3688                                 AtomicBoolean first = new AtomicBoolean(true);
3689
3690                                 @Override
3691                                 public void execute(ReadGraphImpl graph, byte[] result) {
3692                                         try {
3693                                                 if(first.compareAndSet(true, false)) {
3694                                                         procedure.execute(graph, result);
3695 //                                                      impl.state.barrier.dec(this);
3696                                                 } else {
3697                                                         procedure.execute(impl.newRestart(graph), result);
3698                                                 }
3699                                         } catch (Throwable t2) {
3700                                                 Logger.defaultLogError(t2);
3701                                         }
3702                                 }
3703
3704                                 @Override
3705                                 public void exception(ReadGraphImpl graph, Throwable t) {
3706                                         try {
3707                                                 if(first.compareAndSet(true, false)) {
3708                                                         procedure.exception(graph, t);
3709 //                                                      impl.state.barrier.dec(this);
3710                                                 } else {
3711                                                         procedure.exception(impl.newRestart(graph), t);
3712                                                 }
3713                                         } catch (Throwable t2) {
3714                                                 Logger.defaultLogError(t2);
3715                                         }
3716                                 }
3717
3718                         };
3719
3720 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
3721 //                      else impl.state.barrier.inc(null, null);
3722
3723                         try {
3724                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3725                         } catch (DatabaseException e) {
3726                                 throw new IllegalStateException("Internal error");
3727                         }
3728
3729 //              } else {
3730 //
3731 //                      return QueryCacheBase.runnerValueQuery(impl, sId, impl.parent, null, null);
3732 //                      
3733 //              }
3734 //              
3735 //              throw new IllegalStateException("Internal error");
3736
3737         }
3738
3739         @Override
3740         final public void forPossibleValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
3741
3742                 assert(subject != null);
3743                 assert(procedure != null);
3744
3745                 final ListenerBase listener = getListenerBase(procedure);
3746
3747                 if(impl.parent != null || listener != null) {
3748
3749                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3750
3751                                 AtomicBoolean first = new AtomicBoolean(true);
3752
3753                                 @Override
3754                                 public void execute(ReadGraphImpl graph, byte[] result) {
3755                                         try {
3756                                                 if(first.compareAndSet(true, false)) {
3757                                                         procedure.execute(graph, result);
3758 //                                                      impl.state.barrier.dec(this);
3759                                                 } else {
3760                                                         procedure.execute(impl.newRestart(graph), result);
3761                                                 }
3762                                         } catch (Throwable t2) {
3763                                                 Logger.defaultLogError(t2);
3764                                         }
3765                                 }
3766
3767                                 @Override
3768                                 public void exception(ReadGraphImpl graph, Throwable t) {
3769                                         try {
3770                                                 if(first.compareAndSet(true, false)) {
3771                                                         procedure.exception(graph, t);
3772 //                                                      impl.state.barrier.dec(this);
3773                                                 } else {
3774                                                         procedure.exception(impl.newRestart(graph), t);
3775                                                 }
3776                                         } catch (Throwable t2) {
3777                                                 Logger.defaultLogError(t2);
3778                                         }
3779                                 }
3780
3781                         };
3782
3783                         int sId = querySupport.getId(subject);
3784
3785 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
3786 //                      else impl.state.barrier.inc(null, null);
3787
3788                         try {
3789                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3790                         } catch (DatabaseException e) {
3791                                 Logger.defaultLogError(e);
3792                         }
3793
3794                 } else {
3795
3796                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3797
3798                                 @Override
3799                                 public void execute(ReadGraphImpl graph, byte[] result) {
3800
3801                                         procedure.execute(graph, result);
3802
3803                                 }
3804
3805                                 @Override
3806                                 public void exception(ReadGraphImpl graph, Throwable t) {
3807
3808                                         procedure.exception(graph, t);
3809
3810                                 }
3811
3812                         };
3813
3814                         int sId = querySupport.getId(subject);
3815
3816                         try {
3817                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3818                         } catch (DatabaseException e) {
3819                                 Logger.defaultLogError(e);
3820                         }
3821
3822                 }
3823
3824         }
3825
3826         @Override
3827         final public void forInverse(final ReadGraphImpl impl, final Resource relation, final AsyncProcedure<Resource> procedure) {
3828
3829                 assert(relation != null);
3830                 assert(procedure != null);
3831
3832                 final ListenerBase listener = getListenerBase(procedure);
3833
3834                 IntProcedure ip = new IntProcedure() {
3835
3836                         private int result = 0;
3837                         
3838                     final AtomicBoolean found = new AtomicBoolean(false);
3839                     final AtomicBoolean done = new AtomicBoolean(false);
3840
3841                         @Override
3842                         public void finished(ReadGraphImpl graph) {
3843                                 
3844                         // Shall fire exactly once!
3845                         if(done.compareAndSet(false, true)) {
3846                                 try {
3847                                         if(result == 0) {
3848                                                         procedure.exception(graph, new NoInverseException(""));
3849 //                                              impl.state.barrier.dec(this);
3850                                         } else {
3851                                                 procedure.execute(graph, querySupport.getResource(result));
3852 //                                              impl.state.barrier.dec(this);
3853                                         }
3854                                 } catch (Throwable t) {
3855                                         Logger.defaultLogError(t);
3856                                 }
3857                         }
3858                         
3859                         }
3860
3861                         @Override
3862                         public void execute(ReadGraphImpl graph, int i) {
3863                                 
3864                                 if(found.compareAndSet(false, true)) {
3865                                         this.result = i;
3866                                 } else {
3867                                         // Shall fire exactly once!
3868                                         if(done.compareAndSet(false, true)) {
3869                                                 try {
3870                                                         procedure.exception(graph, new ManyObjectsForFunctionalRelationException("Multiple items e.g. " + this.result + " and " + result));
3871 //                                                      impl.state.barrier.dec(this);
3872                                                 } catch (Throwable t) {
3873                                                 Logger.defaultLogError(t);
3874                                                 }
3875                                         }
3876                                 }
3877                                 
3878                         }
3879
3880                         @Override
3881                         public void exception(ReadGraphImpl graph, Throwable t) {
3882                                 // Shall fire exactly once!
3883                                 if(done.compareAndSet(false, true)) {
3884                                         try {
3885                                                 procedure.exception(graph, t);
3886 //                                              impl.state.barrier.dec(this);
3887                                         } catch (Throwable t2) {
3888                                         Logger.defaultLogError(t2);
3889                                         }
3890                                 }
3891                         }
3892
3893                 };
3894
3895                 int sId = querySupport.getId(relation);
3896
3897 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectObjects#" + sId);
3898 //              else impl.state.barrier.inc(null, null);
3899
3900                 try {
3901                         QueryCache.runnerObjects(impl, sId, getInverseOf(), impl.parent, listener, ip);
3902                 } catch (DatabaseException e) {
3903                         Logger.defaultLogError(e);
3904                 }
3905
3906         }
3907
3908         @Override
3909         final public void forResource(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
3910
3911                 assert(id != null);
3912                 assert(procedure != null);
3913
3914                 InternalProcedure<Integer> ip = new InternalProcedure<Integer>() {
3915
3916                         @Override
3917                         public void execute(ReadGraphImpl graph, Integer result) {
3918                                 try {
3919                                         procedure.execute(graph, querySupport.getResource(result));
3920                                 } catch (Throwable t2) {
3921                                         Logger.defaultLogError(t2);
3922                                 }
3923 //                              impl.state.barrier.dec(this);
3924                         }   
3925
3926                         @Override
3927                         public void exception(ReadGraphImpl graph, Throwable t) {
3928
3929                                 try {
3930                                         procedure.exception(graph, t);
3931                                 } catch (Throwable t2) {
3932                                         Logger.defaultLogError(t2);
3933                                 }
3934 //                              impl.state.barrier.dec(this);
3935                         }
3936
3937                 };
3938
3939 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "Resource");
3940 //              else impl.state.barrier.inc(null, null);
3941
3942                 forResource(impl, id, impl.parent, ip);
3943
3944         }
3945
3946         @Override
3947         final public void forBuiltin(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
3948
3949                 assert(id != null);
3950                 assert(procedure != null);
3951
3952 //              impl.state.barrier.inc();
3953
3954                 try {
3955                         forBuiltin(impl, id, impl.parent, new InternalProcedure<Integer>() {
3956
3957                                 @Override
3958                                 public void execute(ReadGraphImpl graph, Integer result) {
3959                                         try {
3960                                                 procedure.execute(graph, querySupport.getResource(result)); 
3961                                         } catch (Throwable t2) {
3962                                                 Logger.defaultLogError(t2);
3963                                         }
3964 //                              impl.state.barrier.dec();
3965                                 }   
3966
3967                                 @Override
3968                                 public void exception(ReadGraphImpl graph, Throwable t) {
3969                                         try {
3970                                                 procedure.exception(graph, t);
3971                                         } catch (Throwable t2) {
3972                                                 Logger.defaultLogError(t2);
3973                                         }
3974 //                              impl.state.barrier.dec();
3975                                 }
3976
3977                         });
3978                 } catch (DatabaseException e) {
3979                         Logger.defaultLogError(e);
3980                 }
3981
3982         }
3983
3984         @Override
3985         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
3986
3987                 assert(subject != null);
3988                 assert(procedure != null);
3989
3990                 final ListenerBase listener = getListenerBase(procedure);
3991
3992                 try {
3993                         IntSet result = QueryCache.resultDirectPredicates(impl, querySupport.getId(subject), impl.parent, listener);
3994                         procedure.execute(impl, !result.isEmpty());
3995                 } catch (DatabaseException e) {
3996                         procedure.exception(impl, e);
3997                 }
3998                         
3999         }
4000
4001         @Override
4002         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Boolean> procedure) {
4003
4004                 assert(subject != null);
4005                 assert(predicate != null);
4006                 assert(procedure != null);
4007
4008                 AsyncMultiProcedure<Resource> ip = new AsyncMultiProcedureAdapter<Resource>() {
4009
4010                         boolean found = false;
4011
4012                         @Override
4013                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
4014                                 found = true;
4015                         }
4016
4017                         @Override
4018                         synchronized public void finished(AsyncReadGraph graph) {
4019                                 try {
4020                                         procedure.execute(graph, found);
4021                                 } catch (Throwable t2) {
4022                                         Logger.defaultLogError(t2);
4023                                 }
4024 //                              impl.state.barrier.dec(this);
4025                         }
4026
4027                         @Override
4028                         public void exception(AsyncReadGraph graph, Throwable t) {
4029                                 try {
4030                                         procedure.exception(graph, t);
4031                                 } catch (Throwable t2) {
4032                                         Logger.defaultLogError(t2);
4033                                 }
4034 //                              impl.state.barrier.dec(this);
4035                         }
4036
4037                 };
4038
4039 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#ForEachObject#" + subject + "#" + predicate);
4040 //              else impl.state.barrier.inc(null, null);
4041
4042                 forEachObject(impl, subject, predicate, ip);
4043
4044         }
4045
4046         @Override
4047         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final Resource object, final AsyncProcedure<Boolean> procedure) {
4048
4049                 assert(subject != null);
4050                 assert(predicate != null);
4051                 assert(procedure != null);
4052
4053 //              impl.state.barrier.inc();
4054
4055                 forEachObject(impl, subject, predicate, new AsyncMultiProcedureAdapter<Resource>() {
4056
4057                         boolean found = false;
4058
4059                         @Override
4060                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
4061                                 if(resource.equals(object)) found = true;
4062                         }
4063
4064                         @Override
4065                         synchronized public void finished(AsyncReadGraph graph) {
4066                                 try {
4067                                         procedure.execute(graph, found);
4068                                 } catch (Throwable t2) {
4069                                         Logger.defaultLogError(t2);
4070                                 }
4071 //                              impl.state.barrier.dec();
4072                         }
4073
4074                         @Override
4075                         public void exception(AsyncReadGraph graph, Throwable t) {
4076                                 try {
4077                                         procedure.exception(graph, t);
4078                                 } catch (Throwable t2) {
4079                                         Logger.defaultLogError(t2);
4080                                 }
4081 //                              impl.state.barrier.dec();
4082                         }
4083
4084                 });
4085
4086         }
4087
4088         @Override
4089         final public void forHasValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
4090
4091                 assert(subject != null);
4092                 assert(procedure != null);
4093
4094                 final ListenerBase listener = getListenerBase(procedure);
4095
4096 //              impl.state.barrier.inc();
4097
4098                 try {
4099                         QueryCache.runnerValueQuery(impl, querySupport.getId(subject), impl.parent, listener, new InternalProcedure<byte[]>() {
4100
4101                                 @Override
4102                                 public void execute(ReadGraphImpl graph, byte[] object) {
4103                                         boolean result = object != null;
4104                                         try {
4105                                                 procedure.execute(graph, result);
4106                                         } catch (Throwable t2) {
4107                                                 Logger.defaultLogError(t2);
4108                                         }
4109 //                              impl.state.barrier.dec();
4110                                 }
4111
4112                                 @Override
4113                                 public void exception(ReadGraphImpl graph, Throwable t) {
4114                                         try {
4115                                                 procedure.exception(graph, t);
4116                                         } catch (Throwable t2) {
4117                                                 Logger.defaultLogError(t2);
4118                                         }
4119 //                              impl.state.barrier.dec();
4120                                 }
4121
4122                         });
4123                 } catch (DatabaseException e) {
4124                         Logger.defaultLogError(e);
4125                 }
4126
4127         }
4128
4129         @Override
4130         final public void forOrderedSet(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
4131
4132                 assert(subject != null);
4133                 assert(procedure != null);
4134
4135                 final ListenerBase listener = getListenerBase(procedure);
4136
4137                 try {
4138                         
4139                         QueryCache.runnerOrderedSet(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
4140
4141                                 @Override
4142                                 public void exception(ReadGraphImpl graph, Throwable t) {
4143                                         try {
4144                                                 procedure.exception(graph, t);
4145                                         } catch (Throwable t2) {
4146                                                 Logger.defaultLogError(t2);
4147                                         }
4148 //                              impl.state.barrier.dec();
4149                                 }
4150
4151                                 @Override
4152                                 public void execute(ReadGraphImpl graph, int i) {
4153                                         try {
4154                                                 procedure.execute(graph, querySupport.getResource(i));
4155                                         } catch (Throwable t2) {
4156                                                 Logger.defaultLogError(t2);
4157                                         }
4158                                 }
4159
4160                                 @Override
4161                                 public void finished(ReadGraphImpl graph) {
4162                                         try {
4163                                                 procedure.finished(graph);
4164                                         } catch (Throwable t2) {
4165                                                 Logger.defaultLogError(t2);
4166                                         }
4167 //                              impl.state.barrier.dec();
4168                                 }
4169
4170                         });
4171                 } catch (DatabaseException e) {
4172                         Logger.defaultLogError(e);
4173                 }
4174
4175         }
4176
4177 //      @Override
4178 //      final public <T> void query(final ReadGraphImpl impl, final AsyncRead<T> request, final CacheEntry parent, final AsyncProcedure<T> procedure, ListenerBase listener) throws DatabaseException {
4179 //
4180 //              assert(request != null);
4181 //              assert(procedure != null);
4182 //
4183 //              QueryCache.runnerAsyncReadEntry(impl, request, parent, listener, procedure);
4184 //
4185 //      }
4186
4187 //      @Override
4188 //      final public <T> T tryQuery(final ReadGraphImpl graph, final Read<T> request) throws DatabaseException {
4189 //
4190 //              assert(graph != null);
4191 //              assert(request != null);
4192 //
4193 //              final ReadEntry entry = (ReadEntry)cache.getCached(request);
4194 //              if(entry != null && entry.isReady()) {
4195 //                  return (T)entry.get(graph, this, null);
4196 //              } else {
4197 //                      return request.perform(graph);
4198 //              }
4199 //
4200 //      }
4201
4202 //    final public <T> T tryQuery(final ReadGraphImpl graph, final ExternalRead<T> request) throws DatabaseException {
4203 //
4204 //        assert(graph != null);
4205 //        assert(request != null);
4206 //
4207 //        final ExternalReadEntry<T> entry = cache.externalReadMap.get(request);
4208 //        if(entry != null && entry.isReady()) {
4209 //            if(entry.isExcepted()) {
4210 //                Throwable t = (Throwable)entry.getResult();
4211 //                if(t instanceof DatabaseException) throw (DatabaseException)t;
4212 //                else throw new DatabaseException(t);
4213 //            } else {
4214 //                return (T)entry.getResult();
4215 //            }            
4216 //        } else {
4217 //
4218 //            final DataContainer<T> result = new DataContainer<T>();
4219 //            final DataContainer<Throwable> exception = new DataContainer<Throwable>();
4220 //            
4221 //            request.register(graph, new Listener<T>() {
4222 //                
4223 //                @Override
4224 //                public void exception(Throwable t) {
4225 //                    exception.set(t);
4226 //                }
4227 //
4228 //                @Override
4229 //                public void execute(T t) {
4230 //                    result.set(t);
4231 //                }
4232 //
4233 //                @Override
4234 //                public boolean isDisposed() {
4235 //                    return true;
4236 //                }
4237 //            
4238 //            });
4239 //            
4240 //            Throwable t = exception.get();
4241 //            if(t != null) {
4242 //                if(t instanceof DatabaseException) throw (DatabaseException)t;
4243 //                else throw new DatabaseException(t);
4244 //            }
4245 //            
4246 //            return result.get();
4247 //
4248 //        }
4249 //
4250 //    }
4251         
4252 //      @Override
4253 //      final public <T> void tryQuery(final ReadGraphImpl graph, final AsyncRead<T> request, AsyncProcedure<T> procedure) {
4254 //
4255 //              assert(graph != null);
4256 //              assert(request != null);
4257 //
4258 //              final AsyncReadEntry entry = cache.asyncReadMap.get(request);
4259 //              if(entry != null && entry.isReady()) {
4260 //                      if(entry.isExcepted()) {
4261 //                              procedure.exception(graph, (Throwable)entry.getResult());
4262 //                      } else {
4263 //                              procedure.execute(graph, (T)entry.getResult());
4264 //                      }
4265 //              } else {
4266 //                      request.perform(graph, procedure);
4267 //              }
4268 //
4269 //      }
4270
4271         @Override
4272         final public <T> void query(final ReadGraphImpl impl, final MultiRead<T> request, final CacheEntry parent, final SyncMultiProcedure<T> procedure, ListenerBase listener) {
4273
4274                 assert(request != null);
4275                 assert(procedure != null);
4276
4277                 try {
4278
4279                         queryMultiRead(impl, request, parent, listener, procedure);
4280                         
4281                 } catch (DatabaseException e) {
4282                         
4283                         throw new IllegalStateException(e);
4284                         
4285                 }
4286
4287         }
4288
4289         @Override
4290         final public <T> void query(final ReadGraphImpl impl, final AsyncMultiRead<T> request, final CacheEntry parent, final AsyncMultiProcedure<T> procedure, ListenerBase listener) {
4291
4292                 assert(request != null);
4293                 assert(procedure != null);
4294
4295 //              impl.state.barrier.inc();
4296
4297                 runAsyncMultiRead(impl, request, parent, listener, new AsyncMultiProcedure<T>() {
4298
4299                         public void execute(AsyncReadGraph graph, T result) {
4300
4301                                 try {
4302                                         procedure.execute(graph, result);
4303                                 } catch (Throwable t2) {
4304                                         Logger.defaultLogError(t2);
4305                                 }
4306                         }
4307
4308                         @Override
4309                         public void finished(AsyncReadGraph graph) {
4310
4311                                 try {
4312                                         procedure.finished(graph);
4313                                 } catch (Throwable t2) {
4314                                         Logger.defaultLogError(t2);
4315                                 }
4316
4317 //                              impl.state.barrier.dec();
4318
4319                         }
4320
4321                         @Override
4322                         public String toString() {
4323                                 return procedure.toString();
4324                         }
4325
4326                         @Override
4327                         public void exception(AsyncReadGraph graph, Throwable t) {
4328
4329                                 try {
4330                                         procedure.exception(graph, t);
4331                                 } catch (Throwable t2) {
4332                                         Logger.defaultLogError(t2);
4333                                 }
4334
4335 //                              impl.state.barrier.dec();
4336
4337                         }
4338
4339                 });
4340
4341         }
4342
4343 //      @Override
4344 //      final public <T> void query(final ReadGraphImpl impl, final ExternalRead<T> request, final CacheEntry parent, final Procedure<T> procedure, ListenerBase listener) throws DatabaseException {
4345 //
4346 //              assert(request != null);
4347 //              assert(procedure != null);
4348 //
4349 //              try {
4350 //              
4351 //                      queryPrimitiveRead(impl, request, parent, listener, new AsyncProcedure<T>() {
4352 //      
4353 //                              @Override
4354 //                              public String toString() {
4355 //                                      return procedure.toString();
4356 //                              }
4357 //      
4358 //                              @Override
4359 //                              public void execute(AsyncReadGraph graph, T result) {
4360 //                                      try {
4361 //                                              procedure.execute(result);
4362 //                                      } catch (Throwable t2) {
4363 //                                              Logger.defaultLogError(t2);
4364 //                                      }
4365 //                              }
4366 //
4367 //                              @Override
4368 //                              public void exception(AsyncReadGraph graph, Throwable throwable) {
4369 //                                      try {
4370 //                                              procedure.exception(throwable);
4371 //                                      } catch (Throwable t2) {
4372 //                                              Logger.defaultLogError(t2);
4373 //                                      }
4374 //                              }
4375 //      
4376 //                      });
4377 //                      
4378 //              } catch (DatabaseException e) {
4379 //                      
4380 //                      throw new IllegalStateException(e);
4381 //                      
4382 //              }
4383 //
4384 //      }
4385
4386         @Override
4387         public VirtualGraph getProvider(Resource subject, Resource predicate, Resource object) {
4388                 
4389                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
4390                 
4391         }
4392         
4393         @Override
4394         public VirtualGraph getProvider(Resource subject, Resource predicate) {
4395                 
4396                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate));
4397                 
4398         }
4399
4400         @Override
4401         public VirtualGraph getValueProvider(Resource subject) {
4402                 
4403                 return querySupport.getValueProvider(querySupport.getId(subject));
4404                 
4405         }
4406
4407         public boolean resumeTasks(ReadGraphImpl graph) {
4408
4409                 return querySupport.resume(graph);
4410
4411         }
4412         
4413         public boolean isImmutable(int resourceId) {
4414                 return querySupport.isImmutable(resourceId);
4415         }
4416
4417         public boolean isImmutable(Resource resource) {
4418                 ResourceImpl impl = (ResourceImpl)resource;
4419                 return isImmutable(impl.id);
4420         }
4421         
4422         private Layer0 L0;
4423         
4424         public Layer0 getL0(ReadGraph graph) {
4425                 if(L0 == null) {
4426                         L0 = Layer0.getInstance(graph);
4427                 }
4428                 return L0;
4429         }
4430
4431     public static ThreadLocal<Integer> thread = new ThreadLocal<Integer>() {
4432         protected Integer initialValue() {
4433             return -1;
4434         }
4435     };
4436         
4437 }