]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java
Merge "Trying to wait for procedures"
[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                 throw new UnsupportedOperationException();
2300
2301 //              assert(subject != null);
2302 //              assert(procedure != null);
2303 //
2304 //              final ListenerBase listener = getListenerBase(procedure);
2305 //
2306 //              IntProcedure ip = new IntProcedure() {
2307 //
2308 //                      AtomicBoolean first = new AtomicBoolean(true);
2309 //
2310 //                      @Override
2311 //                      public void execute(ReadGraphImpl graph, int i) {
2312 //                              try {
2313 //                                      if(first.get()) {
2314 //                                              procedure.execute(graph, querySupport.getResource(i));
2315 //                                      } else {
2316 //                                              procedure.execute(impl.newRestart(graph), querySupport.getResource(i));
2317 //                                      }
2318 //                              } catch (Throwable t2) {
2319 //                                      Logger.defaultLogError(t2);
2320 //                              }
2321 //                      }
2322 //
2323 //                      @Override
2324 //                      public void finished(ReadGraphImpl graph) {
2325 //                              try {
2326 //                                      if(first.compareAndSet(true, false)) {
2327 //                                              procedure.finished(graph);
2328 ////                                            impl.state.barrier.dec(this);
2329 //                                      } else {
2330 //                                              procedure.finished(impl.newRestart(graph));
2331 //                                      }
2332 //
2333 //                              } catch (Throwable t2) {
2334 //                                      Logger.defaultLogError(t2);
2335 //                              }
2336 //                      }
2337 //
2338 //                      @Override
2339 //                      public void exception(ReadGraphImpl graph, Throwable t) {
2340 //                              try {
2341 //                                      if(first.compareAndSet(true, false)) {
2342 //                                              procedure.exception(graph, t);
2343 //                                      } else {
2344 //                                              procedure.exception(impl.newRestart(graph), t);
2345 //                                      }
2346 //                              } catch (Throwable t2) {
2347 //                                      Logger.defaultLogError(t2);
2348 //                              }
2349 //                      }
2350 //
2351 //              };
2352 //
2353 //              int sId = querySupport.getId(subject);
2354 //
2355 //              try {
2356 //                      QueryCache.runnerPredicates(impl, sId, impl.parent, listener, ip);
2357 //              } catch (DatabaseException e) {
2358 //                      Logger.defaultLogError(e);
2359 //              }
2360
2361         }
2362
2363         @Override
2364         final public void forEachPredicate(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
2365                 
2366                 throw new UnsupportedOperationException();
2367
2368 //              assert(subject != null);
2369 //              assert(procedure != null);
2370 //
2371 //              final ListenerBase listener = getListenerBase(procedure);
2372 //
2373 //              try {
2374 //                      QueryCache.runnerPredicates(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
2375 //
2376 //                              @Override
2377 //                              public void execute(ReadGraphImpl graph, int i) {
2378 //                                      try {
2379 //                                              procedure.execute(querySupport.getResource(i));
2380 //                                      } catch (Throwable t2) {
2381 //                                              Logger.defaultLogError(t2);
2382 //                                      }
2383 //                              }
2384 //
2385 //                              @Override
2386 //                              public void finished(ReadGraphImpl graph) {
2387 //                                      try {
2388 //                                              procedure.finished();
2389 //                                      } catch (Throwable t2) {
2390 //                                              Logger.defaultLogError(t2);
2391 //                                      }
2392 ////                            impl.state.barrier.dec();
2393 //                              }
2394 //
2395 //                              @Override
2396 //                              public void exception(ReadGraphImpl graph, Throwable t) {
2397 //                                      try {
2398 //                                              procedure.exception(t);
2399 //                                      } catch (Throwable t2) {
2400 //                                              Logger.defaultLogError(t2);
2401 //                                      }
2402 ////                            impl.state.barrier.dec();
2403 //                              }
2404 //
2405 //                      });
2406 //              } catch (DatabaseException e) {
2407 //                      Logger.defaultLogError(e);
2408 //              }
2409
2410         }
2411         
2412         @Override
2413         final public IntSet getPredicates(final ReadGraphImpl impl, final Resource subject) throws Throwable {
2414                 return QueryCacheBase.resultPredicates(impl, querySupport.getId(subject), impl.parent, null); 
2415         }
2416
2417         @Override
2418         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2419                         final Resource predicate, final MultiProcedure<Statement> procedure) {
2420
2421                 assert(subject != null);
2422                 assert(predicate != null);
2423                 assert(procedure != null);
2424
2425                 final ListenerBase listener = getListenerBase(procedure);
2426
2427 //              impl.state.barrier.inc();
2428
2429                 try {
2430                         Statements.queryEach(impl, querySupport.getId(subject), querySupport.getId(predicate), this, impl.parent, listener, new TripleIntProcedureAdapter() {
2431
2432                                 @Override
2433                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
2434                                         try {
2435                                                 procedure.execute(querySupport.getStatement(s, p, o));
2436                                         } catch (Throwable t2) {
2437                                                 Logger.defaultLogError(t2);
2438                                         }
2439                                 }
2440
2441                                 @Override
2442                                 public void finished(ReadGraphImpl graph) {
2443                                         try {
2444                                                 procedure.finished();
2445                                         } catch (Throwable t2) {
2446                                                 Logger.defaultLogError(t2);
2447                                         }
2448 //                              impl.state.barrier.dec();
2449                                 }
2450
2451                                 @Override
2452                                 public void exception(ReadGraphImpl graph, Throwable t) {
2453                                         try {
2454                                                 procedure.exception(t);
2455                                         } catch (Throwable t2) {
2456                                                 Logger.defaultLogError(t2);
2457                                         }
2458 //                              impl.state.barrier.dec();
2459                                 }
2460
2461                         });
2462                 } catch (DatabaseException e) {
2463                         Logger.defaultLogError(e);
2464                 }
2465
2466         }
2467
2468         @Override
2469         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2470                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
2471
2472                 assert(subject != null);
2473                 assert(predicate != null);
2474                 assert(procedure != null);
2475
2476                 final ListenerBase listener = getListenerBase(procedure);
2477
2478                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
2479
2480                         boolean first = true;
2481
2482                         @Override
2483                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
2484                                 try {
2485                                         if(first) {
2486                                                 procedure.execute(graph, querySupport.getStatement(s, p, o));
2487                                         } else {
2488                                                 procedure.execute(impl.newRestart(graph), querySupport.getStatement(s, p, o));
2489                                         }
2490                                 } catch (Throwable t2) {
2491                                         Logger.defaultLogError(t2);
2492                                 }
2493                         }
2494
2495                         @Override
2496                         public void finished(ReadGraphImpl graph) {
2497
2498                                 try {
2499                                         if(first) {
2500                                                 first = false;
2501                                                 procedure.finished(graph);
2502 //                                              impl.state.barrier.dec(this);
2503                                         } else {
2504                                                 procedure.finished(impl.newRestart(graph));
2505                                         }
2506                                 } catch (Throwable t2) {
2507                                         Logger.defaultLogError(t2);
2508                                 }
2509
2510                         }
2511
2512                         @Override
2513                         public void exception(ReadGraphImpl graph, Throwable t) {
2514
2515                                 try {
2516                                         if(first) {
2517                                                 first = false;
2518                                                 procedure.exception(graph, t);
2519 //                                              impl.state.barrier.dec(this);
2520                                         } else {
2521                                                 procedure.exception(impl.newRestart(graph), t);
2522                                         }
2523                                 } catch (Throwable t2) {
2524                                         Logger.defaultLogError(t2);
2525                                 }
2526
2527                         }
2528
2529                 };
2530
2531                 int sId = querySupport.getId(subject);
2532                 int pId = querySupport.getId(predicate);
2533
2534 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
2535 //              else impl.state.barrier.inc(null, null);
2536
2537                 try {
2538                         Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
2539                 } catch (DatabaseException e) {
2540                         Logger.defaultLogError(e);
2541                 }
2542
2543         }
2544
2545         @Override
2546         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2547                         final Resource predicate, final StatementProcedure procedure) {
2548
2549                 assert(subject != null);
2550                 assert(predicate != null);
2551                 assert(procedure != null);
2552
2553                 final ListenerBase listener = getListenerBase(procedure);
2554
2555                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
2556
2557                         boolean first = true;
2558
2559                         @Override
2560                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
2561                                 try {
2562                                         if(first) {
2563                                                 procedure.execute(graph, s, p, o);
2564                                         } else {
2565                                                 procedure.execute(impl.newRestart(graph), s, p, o);
2566                                         }
2567                                 } catch (Throwable t2) {
2568                                         Logger.defaultLogError(t2);
2569                                 }
2570                         }
2571
2572                         @Override
2573                         public void finished(ReadGraphImpl graph) {
2574
2575                                 try {
2576                                         if(first) {
2577                                                 first = false;
2578                                                 procedure.finished(graph);
2579 //                                              impl.state.barrier.dec(this);
2580                                         } else {
2581                                                 procedure.finished(impl.newRestart(graph));
2582                                         }
2583                                 } catch (Throwable t2) {
2584                                         Logger.defaultLogError(t2);
2585                                 }
2586
2587                         }
2588
2589                         @Override
2590                         public void exception(ReadGraphImpl graph, Throwable t) {
2591
2592                                 try {
2593                                         if(first) {
2594                                                 first = false;
2595                                                 procedure.exception(graph, t);
2596 //                                              impl.state.barrier.dec(this);
2597                                         } else {
2598                                                 procedure.exception(impl.newRestart(graph), t);
2599                                         }
2600                                 } catch (Throwable t2) {
2601                                         Logger.defaultLogError(t2);
2602                                 }
2603
2604                         }
2605
2606                 };
2607
2608                 int sId = querySupport.getId(subject);
2609                 int pId = querySupport.getId(predicate);
2610
2611 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
2612 //              else impl.state.barrier.inc(null, null);
2613
2614                 try {
2615                         Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
2616                 } catch (DatabaseException e) {
2617                         Logger.defaultLogError(e);
2618                 }
2619
2620         }
2621         
2622         @Override
2623         final public void forStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
2624
2625                 assert(subject != null);
2626                 assert(predicate != null);
2627                 assert(procedure != null);
2628
2629                 forEachStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
2630
2631                         private Set<Statement> current = null;
2632                         private Set<Statement> run = new HashSet<Statement>();
2633
2634                         @Override
2635                         public void execute(AsyncReadGraph graph, Statement result) {
2636
2637                                 boolean found = false;
2638
2639                                 if(current != null) {
2640
2641                                         found = current.remove(result);
2642
2643                                 }
2644
2645                                 if(!found) procedure.add(graph, result);
2646
2647                                 run.add(result);
2648
2649                         }
2650
2651                         @Override
2652                         public void finished(AsyncReadGraph graph) {
2653
2654                                 if(current != null) { 
2655                                         for(Statement r : current) procedure.remove(graph, r);
2656                                 }
2657
2658                                 current = run;
2659
2660                                 run = new HashSet<Statement>();
2661
2662                         }
2663
2664                         @Override
2665                         public void exception(AsyncReadGraph graph, Throwable t) {
2666                                 procedure.exception(graph, t);
2667                         }
2668
2669                         @Override
2670                         public boolean isDisposed() {
2671                                 return procedure.isDisposed();
2672                         }
2673
2674                 });
2675
2676         }
2677
2678         @Override
2679         final public void forEachAssertedStatement(final ReadGraphImpl impl, final Resource subject,
2680                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
2681
2682                 assert(subject != null);
2683                 assert(predicate != null);
2684                 assert(procedure != null);
2685
2686                 final ListenerBase listener = getListenerBase(procedure);
2687
2688 //              impl.state.barrier.inc();
2689
2690                 try {
2691                         QueryCache.runnerAssertedStatements(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new TripleIntProcedureAdapter() {
2692
2693                                 @Override
2694                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
2695                                         try {
2696                                                 procedure.execute(graph, querySupport.getStatement(s, p, o));
2697                                         } catch (Throwable t2) {
2698                                                 Logger.defaultLogError(t2);
2699                                         }
2700                                 }
2701
2702                                 @Override
2703                                 public void finished(ReadGraphImpl graph) {
2704                                         try {
2705                                                 procedure.finished(graph);
2706                                         } catch (Throwable t2) {
2707                                                 Logger.defaultLogError(t2);
2708                                         }
2709 //                              impl.state.barrier.dec();
2710                                 }
2711
2712                                 @Override
2713                                 public void exception(ReadGraphImpl graph, Throwable t) {
2714                                         try {
2715                                                 procedure.exception(graph, t);
2716                                         } catch (Throwable t2) {
2717                                                 Logger.defaultLogError(t2);
2718                                         }
2719 //                              impl.state.barrier.dec();
2720                                 }
2721
2722                         });
2723                 } catch (DatabaseException e) {
2724                         Logger.defaultLogError(e);
2725                 }
2726
2727         }
2728
2729         private static ListenerBase getListenerBase(Object procedure) {
2730                 if(procedure instanceof ListenerBase) return (ListenerBase)procedure;
2731                 else return null;
2732         }
2733
2734         @Override
2735         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final MultiProcedure<Resource> procedure) {
2736
2737                 assert(subject != null);
2738                 assert(predicate != null);
2739                 assert(procedure != null);
2740
2741                 final ListenerBase listener = getListenerBase(procedure);
2742
2743 //              impl.state.barrier.inc();
2744
2745                 try {
2746                         QueryCache.runnerObjects(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new IntProcedure() {
2747
2748                                 @Override
2749                                 public void execute(ReadGraphImpl graph, int i) {
2750                                         try {
2751                                                 procedure.execute(querySupport.getResource(i));
2752                                         } catch (Throwable t2) {
2753                                                 Logger.defaultLogError(t2);
2754                                         }
2755                                 }
2756
2757                                 @Override
2758                                 public void finished(ReadGraphImpl graph) {
2759                                         try {
2760                                                 procedure.finished();
2761                                         } catch (Throwable t2) {
2762                                                 Logger.defaultLogError(t2);
2763                                         }
2764 //                              impl.state.barrier.dec();
2765                                 }
2766
2767                                 @Override
2768                                 public void exception(ReadGraphImpl graph, Throwable t) {
2769                                         System.out.println("forEachObject exception " + t);
2770                                         try {
2771                                                 procedure.exception(t);
2772                                         } catch (Throwable t2) {
2773                                                 Logger.defaultLogError(t2);
2774                                         }
2775 //                              impl.state.barrier.dec();
2776                                 }
2777
2778                         });
2779                 } catch (DatabaseException e) {
2780                         Logger.defaultLogError(e);
2781                 }
2782
2783         }
2784
2785         @Override
2786         final public void forEachDirectPredicate(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
2787
2788                 assert(subject != null);
2789                 assert(procedure != null);
2790
2791                 final ListenerBase listener = getListenerBase(procedure);
2792
2793                 int sId = querySupport.getId(subject);
2794
2795                 try {
2796                         QueryCache.runnerDirectPredicates(impl, sId, impl.parent, listener, new InternalProcedure<IntSet>() {
2797
2798                                 @Override
2799                                 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
2800                                         procedure.execute(graph, result);
2801                                 }
2802
2803                                 @Override
2804                                 public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
2805                                         procedure.exception(graph, throwable);
2806                                 }
2807                                 
2808                         });
2809                 } catch (DatabaseException e) {
2810                         Logger.defaultLogError(e);
2811                 }
2812
2813         }
2814
2815         final public DirectStatements getDirectStatements(final ReadGraphImpl impl, final Resource subject, final boolean ignoreVirtual) {
2816
2817 //              assert(subject != null);
2818 //              assert(procedure != null);
2819 //
2820 //              final ListenerBase listener = getListenerBase(procedure);
2821 //
2822 //              org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
2823                 
2824                 return querySupport.getStatements(impl, querySupport.getId(subject), this, ignoreVirtual);
2825
2826         }
2827
2828 //      @Override
2829 //      final public void forEachDirectStatement(final ReadGraphImpl impl, final Resource subject, final SyncProcedure<DirectStatements> procedure, boolean ignoreVirtual) {
2830 //
2831 //              assert(subject != null);
2832 //              assert(procedure != null);
2833 //
2834 //              final ListenerBase listener = getListenerBase(procedure);
2835 //
2836 //              org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure, ignoreVirtual);
2837 //
2838 //      }
2839         
2840         private static final Resource INVALID_RESOURCE = new ResourceImpl(null, Integer.MIN_VALUE);
2841
2842         @Override
2843         final public void forPossibleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Resource> procedure) {
2844
2845                 forEachObject(impl, subject, predicate, new AsyncMultiProcedure<Resource>() {
2846
2847                         private Resource single = null;
2848
2849                         @Override
2850                         public synchronized void execute(AsyncReadGraph graph, Resource result) {
2851                                 if(single == null) {
2852                                         single = result;
2853                                 } else {
2854                                         single = INVALID_RESOURCE;
2855                                 }
2856                         }
2857
2858                         @Override
2859                         public synchronized void finished(AsyncReadGraph graph) {
2860                                 if(single == null || single == INVALID_RESOURCE) procedure.execute(graph, null);
2861                                 else procedure.execute(graph, single);
2862                         }
2863
2864                         @Override
2865                         public synchronized void exception(AsyncReadGraph graph, Throwable throwable) {
2866                                 procedure.exception(graph, throwable);
2867                         }
2868
2869                 });
2870
2871         }
2872
2873         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final ListenerBase listener, final IntProcedure procedure) {
2874                 
2875                 final int sId = querySupport.getId(subject);
2876                 final int pId = querySupport.getId(predicate);
2877
2878                 try {
2879                         QueryCache.runnerObjects(impl, sId, pId, impl.parent, listener, procedure);
2880                 } catch (DatabaseException e) {
2881                         Logger.defaultLogError(e);
2882                 }
2883                 
2884         }
2885         
2886         static class Runner2Procedure implements IntProcedure {
2887             
2888             public int single = 0;
2889             public Throwable t = null;
2890
2891             public void clear() {
2892                 single = 0;
2893                 t = null;
2894             }
2895             
2896         @Override
2897         public void execute(ReadGraphImpl graph, int i) {
2898             if(single == 0) single = i;
2899             else single = -1;
2900         }
2901
2902         @Override
2903         public void finished(ReadGraphImpl graph) {
2904             if(single == -1) single = 0;
2905         }
2906
2907         @Override
2908         public void exception(ReadGraphImpl graph, Throwable throwable) {
2909             single = 0;
2910             this.t = throwable;
2911         }
2912         
2913         public int get() throws DatabaseException {
2914             if(t != null) {
2915                 if(t instanceof DatabaseException) throw (DatabaseException)t;
2916                 else throw new DatabaseException(t);
2917             }
2918             return single;
2919         }
2920             
2921         }
2922         
2923         final public int getSingleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate) throws DatabaseException {
2924                 
2925                 final int sId = querySupport.getId(subject);
2926                 final int pId = querySupport.getId(predicate);
2927
2928                 Runner2Procedure proc = new Runner2Procedure();
2929                 QueryCache.runnerObjects(impl, sId, pId, impl.parent, null, proc);
2930                 return proc.get();
2931             
2932         }
2933
2934         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
2935
2936                 assert(subject != null);
2937                 assert(predicate != null);
2938
2939                 final ListenerBase listener = getListenerBase(procedure);
2940
2941                 if(impl.parent != null || listener != null) {
2942
2943                         IntProcedure ip = new IntProcedure() {
2944
2945                                 AtomicBoolean first = new AtomicBoolean(true);
2946
2947                                 @Override
2948                                 public void execute(ReadGraphImpl graph, int i) {
2949                                         try {
2950                                                 if(first.get()) {
2951                                                         procedure.execute(impl, querySupport.getResource(i));
2952                                                 } else {
2953                                                         procedure.execute(impl.newRestart(graph), querySupport.getResource(i));
2954                                                 }
2955                                         } catch (Throwable t2) {
2956                                                 Logger.defaultLogError(t2);
2957                                         }
2958
2959                                 }
2960
2961                                 @Override
2962                                 public void finished(ReadGraphImpl graph) {
2963                                         try {
2964                                                 if(first.compareAndSet(true, false)) {
2965                                                         procedure.finished(impl);
2966 //                                                      impl.state.barrier.dec(this);
2967                                                 } else {
2968                                                         procedure.finished(impl.newRestart(graph));
2969                                                 }
2970                                         } catch (Throwable t2) {
2971                                                 Logger.defaultLogError(t2);
2972                                         }
2973                                 }
2974
2975                                 @Override
2976                                 public void exception(ReadGraphImpl graph, Throwable t) {
2977                                         try {
2978                                                 procedure.exception(graph, t);
2979                                         } catch (Throwable t2) {
2980                                                 Logger.defaultLogError(t2);
2981                                         }
2982 //                                      impl.state.barrier.dec(this);
2983                                 }
2984
2985                                 @Override
2986                                 public String toString() {
2987                                         return "forEachObject with " + procedure;
2988                                 }
2989
2990                         };
2991
2992 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Objects" + subject + "#" + predicate);
2993 //                      else impl.state.barrier.inc(null, null);
2994
2995                         forEachObject(impl, subject, predicate, listener, ip);
2996
2997                 } else {
2998
2999                         IntProcedure ip = new IntProcedure() {
3000
3001                                 @Override
3002                                 public void execute(ReadGraphImpl graph, int i) {
3003                                         procedure.execute(graph, querySupport.getResource(i));
3004                                 }
3005
3006                                 @Override
3007                                 public void finished(ReadGraphImpl graph) {
3008                                         procedure.finished(graph);
3009                                 }
3010
3011                                 @Override
3012                                 public void exception(ReadGraphImpl graph, Throwable t) {
3013                                         procedure.exception(graph, t);
3014                                 }
3015
3016                                 @Override
3017                                 public String toString() {
3018                                         return "forEachObject with " + procedure;
3019                                 }
3020
3021                         };
3022
3023                         forEachObject(impl, subject, predicate, listener, ip);
3024
3025                 }
3026
3027         }
3028
3029         @Override
3030         final public void forObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
3031
3032                 assert(subject != null);
3033                 assert(predicate != null);
3034                 assert(procedure != null);
3035
3036                 forEachObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
3037
3038                         private Set<Resource> current = null;
3039                         private Set<Resource> run = new HashSet<Resource>();
3040
3041                         @Override
3042                         public void execute(AsyncReadGraph graph, Resource result) {
3043
3044                                 boolean found = false;
3045
3046                                 if(current != null) {
3047
3048                                         found = current.remove(result);
3049
3050                                 }
3051
3052                                 if(!found) procedure.add(graph, result);
3053
3054                                 run.add(result);
3055
3056                         }
3057
3058                         @Override
3059                         public void finished(AsyncReadGraph graph) {
3060
3061                                 if(current != null) { 
3062                                         for(Resource r : current) procedure.remove(graph, r);
3063                                 }
3064
3065                                 current = run;
3066
3067                                 run = new HashSet<Resource>();
3068
3069                         }
3070
3071                         @Override
3072                         public boolean isDisposed() {
3073                                 return procedure.isDisposed();
3074                         }
3075
3076                         @Override
3077                         public void exception(AsyncReadGraph graph, Throwable t) {
3078                                 procedure.exception(graph, t);
3079                         }
3080
3081                         @Override
3082                         public String toString() {
3083                                 return "forObjectSet " + procedure;
3084                         }
3085
3086                 });
3087
3088         }
3089
3090         @Override
3091         final public void forPredicateSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
3092
3093                 assert(subject != null);
3094                 assert(procedure != null);
3095
3096                 forEachPredicate(impl, subject, new AsyncMultiListener<Resource>() {
3097
3098                         private Set<Resource> current = null;
3099                         private Set<Resource> run = new HashSet<Resource>();
3100
3101                         @Override
3102                         public void execute(AsyncReadGraph graph, Resource result) {
3103
3104                                 boolean found = false;
3105
3106                                 if(current != null) {
3107
3108                                         found = current.remove(result);
3109
3110                                 }
3111
3112                                 if(!found) procedure.add(graph, result);
3113
3114                                 run.add(result);
3115
3116                         }
3117
3118                         @Override
3119                         public void finished(AsyncReadGraph graph) {
3120
3121                                 if(current != null) { 
3122                                         for(Resource r : current) procedure.remove(graph, r);
3123                                 }
3124
3125                                 current = run;
3126
3127                                 run = new HashSet<Resource>();
3128
3129                         }
3130
3131                         @Override
3132                         public boolean isDisposed() {
3133                                 return procedure.isDisposed();
3134                         }
3135
3136                         @Override
3137                         public void exception(AsyncReadGraph graph, Throwable t) {
3138                                 procedure.exception(graph, t);
3139                         }
3140
3141                         @Override
3142                         public String toString() {
3143                                 return "forPredicateSet " + procedure;
3144                         }
3145
3146                 });
3147
3148         }
3149
3150         @Override
3151         final public void forPrincipalTypeSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
3152
3153                 assert(subject != null);
3154                 assert(procedure != null);
3155
3156                 forEachPrincipalType(impl, subject, new AsyncMultiListener<Resource>() {
3157
3158                         private Set<Resource> current = null;
3159                         private Set<Resource> run = new HashSet<Resource>();
3160
3161                         @Override
3162                         public void execute(AsyncReadGraph graph, Resource result) {
3163
3164                                 boolean found = false;
3165
3166                                 if(current != null) {
3167
3168                                         found = current.remove(result);
3169
3170                                 }
3171
3172                                 if(!found) procedure.add(graph, result);
3173
3174                                 run.add(result);
3175
3176                         }
3177
3178                         @Override
3179                         public void finished(AsyncReadGraph graph) {
3180
3181                                 if(current != null) { 
3182                                         for(Resource r : current) procedure.remove(graph, r);
3183                                 }
3184
3185                                 current = run;
3186
3187                                 run = new HashSet<Resource>();
3188
3189                         }
3190
3191                         @Override
3192                         public boolean isDisposed() {
3193                                 return procedure.isDisposed();
3194                         }
3195
3196                         @Override
3197                         public void exception(AsyncReadGraph graph, Throwable t) {
3198                                 procedure.exception(graph, t);
3199                         }
3200
3201                         @Override
3202                         public String toString() {
3203                                 return "forPrincipalTypeSet " + procedure;
3204                         }
3205
3206                 });
3207
3208         }
3209
3210         @Override
3211         final public void forAssertedObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
3212
3213                 assert(subject != null);
3214                 assert(predicate != null);
3215                 assert(procedure != null);
3216
3217                 forEachAssertedObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
3218
3219                         private Set<Resource> current = null;
3220                         private Set<Resource> run = new HashSet<Resource>();
3221
3222                         @Override
3223                         public void execute(AsyncReadGraph graph, Resource result) {
3224
3225                                 boolean found = false;
3226
3227                                 if(current != null) {
3228
3229                                         found = current.remove(result);
3230
3231                                 }
3232
3233                                 if(!found) procedure.add(graph, result);
3234
3235                                 run.add(result);
3236
3237                         }
3238
3239                         @Override
3240                         public void finished(AsyncReadGraph graph) {
3241
3242                                 if(current != null) { 
3243                                         for(Resource r : current) procedure.remove(graph, r);
3244                                 }
3245
3246                                 current = run;
3247
3248                                 run = new HashSet<Resource>();
3249
3250                         }
3251
3252                         @Override
3253                         public boolean isDisposed() {
3254                                 return procedure.isDisposed();
3255                         }
3256
3257                         @Override
3258                         public void exception(AsyncReadGraph graph, Throwable t) {
3259                                 procedure.exception(graph, t);
3260                         }
3261
3262                         @Override
3263                         public String toString() {
3264                                 return "forObjectSet " + procedure;
3265                         }
3266
3267                 });
3268
3269         }
3270
3271         @Override
3272         final public void forAssertedStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
3273
3274                 assert(subject != null);
3275                 assert(predicate != null);
3276                 assert(procedure != null);
3277
3278                 forEachAssertedStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
3279
3280                         private Set<Statement> current = null;
3281                         private Set<Statement> run = new HashSet<Statement>();
3282
3283                         @Override
3284                         public void execute(AsyncReadGraph graph, Statement result) {
3285
3286                                 boolean found = false;
3287
3288                                 if(current != null) {
3289
3290                                         found = current.remove(result);
3291
3292                                 }
3293
3294                                 if(!found) procedure.add(graph, result);
3295
3296                                 run.add(result);
3297
3298                         }
3299
3300                         @Override
3301                         public void finished(AsyncReadGraph graph) {
3302
3303                                 if(current != null) { 
3304                                         for(Statement s : current) procedure.remove(graph, s);
3305                                 }
3306
3307                                 current = run;
3308
3309                                 run = new HashSet<Statement>();
3310
3311                         }
3312
3313                         @Override
3314                         public boolean isDisposed() {
3315                                 return procedure.isDisposed();
3316                         }
3317
3318                         @Override
3319                         public void exception(AsyncReadGraph graph, Throwable t) {
3320                                 procedure.exception(graph, t);
3321                         }
3322
3323                         @Override
3324                         public String toString() {
3325                                 return "forStatementSet " + procedure;
3326                         }
3327
3328                 });
3329
3330         }
3331
3332         @Override
3333         final public void forEachAssertedObject(final ReadGraphImpl impl, final Resource subject,
3334                         final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
3335
3336                 assert(subject != null);
3337                 assert(predicate != null);
3338                 assert(procedure != null);
3339
3340                 final ListenerBase listener = getListenerBase(procedure);
3341
3342                 try {
3343                         QueryCache.runnerAssertedStatements(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new TripleIntProcedure() {
3344
3345                                 @Override
3346                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
3347                                         try {
3348                                                 procedure.execute(graph, querySupport.getResource(o));
3349                                         } catch (Throwable t2) {
3350                                                 Logger.defaultLogError(t2);
3351                                         }
3352                                 }
3353
3354                                 @Override
3355                                 public void finished(ReadGraphImpl graph) {
3356                                         try {               
3357                                                 procedure.finished(graph);
3358                                         } catch (Throwable t2) {
3359                                                 Logger.defaultLogError(t2);
3360                                         }
3361 //                              impl.state.barrier.dec();
3362                                 }
3363
3364                                 @Override
3365                                 public void exception(ReadGraphImpl graph, Throwable t) {
3366                                         try {
3367                                                 procedure.exception(graph, t);
3368                                         } catch (Throwable t2) {
3369                                                 Logger.defaultLogError(t2);
3370                                         }
3371 //                              impl.state.barrier.dec();
3372                                 }
3373
3374                         });
3375                 } catch (DatabaseException e) {
3376                         Logger.defaultLogError(e);
3377                 }
3378
3379         }
3380
3381         @Override
3382         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3383
3384                 assert(subject != null);
3385                 assert(procedure != null);
3386
3387                 final ListenerBase listener = getListenerBase(procedure);
3388
3389                 IntProcedure ip = new IntProcedure() {
3390
3391                         @Override
3392                         public void execute(ReadGraphImpl graph, int i) {
3393                                 try {
3394                                         procedure.execute(graph, querySupport.getResource(i));
3395                                 } catch (Throwable t2) {
3396                                         Logger.defaultLogError(t2);
3397                                 }
3398                         }
3399
3400                         @Override
3401                         public void finished(ReadGraphImpl graph) {
3402                                 try {
3403                                         procedure.finished(graph);
3404                                 } catch (Throwable t2) {
3405                                         Logger.defaultLogError(t2);
3406                                 }
3407 //                              impl.state.barrier.dec(this);
3408                         }
3409
3410                         @Override
3411                         public void exception(ReadGraphImpl graph, Throwable t) {
3412                                 try {
3413                                         procedure.exception(graph, t);
3414                                 } catch (Throwable t2) {
3415                                         Logger.defaultLogError(t2);
3416                                 }
3417 //                              impl.state.barrier.dec(this);
3418                         }
3419
3420                 };
3421
3422                 int sId = querySupport.getId(subject);
3423
3424 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#PrincipalTypes#" + sId);
3425 //              else impl.state.barrier.inc(null, null);
3426
3427                 try {
3428                         QueryCache.runnerPrincipalTypes(impl, sId, impl.parent, listener, ip);
3429                 } catch (DatabaseException e) {
3430                         Logger.defaultLogError(e);
3431                 }
3432
3433         }
3434
3435         @Override
3436         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
3437
3438                 assert(subject != null);
3439                 assert(procedure != null);
3440
3441                 final ListenerBase listener = getListenerBase(procedure);
3442
3443 //              impl.state.barrier.inc();
3444
3445                 try {
3446                         QueryCache.runnerPrincipalTypes(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
3447
3448                                 @Override
3449                                 public void execute(ReadGraphImpl graph, int i) {
3450                                         try {
3451                                                 procedure.execute(querySupport.getResource(i));
3452                                         } catch (Throwable t2) {
3453                                                 Logger.defaultLogError(t2);
3454                                         }
3455                                 }
3456
3457                                 @Override
3458                                 public void finished(ReadGraphImpl graph) {
3459                                         try {
3460                                                 procedure.finished();
3461                                         } catch (Throwable t2) {
3462                                                 Logger.defaultLogError(t2);
3463                                         }
3464 //                              impl.state.barrier.dec();
3465                                 }
3466
3467                                 @Override
3468                                 public void exception(ReadGraphImpl graph, Throwable t) {
3469                                         try {
3470                                                 procedure.exception(t);
3471                                         } catch (Throwable t2) {
3472                                                 Logger.defaultLogError(t2);
3473                                         }
3474 //                              impl.state.barrier.dec();
3475                                 }
3476
3477                         });
3478                 } catch (DatabaseException e) {
3479                         Logger.defaultLogError(e);
3480                 }
3481         }
3482
3483     final public void forTypes(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         assert(listener == null);
3490
3491         InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
3492
3493             @Override
3494             public void execute(final ReadGraphImpl graph, IntSet set) {
3495                 procedure.execute(graph, set);
3496             }
3497
3498             @Override
3499             public void exception(ReadGraphImpl graph, Throwable t) {
3500                 procedure.exception(graph, t);
3501             }
3502
3503         };
3504
3505         int sId = querySupport.getId(subject);
3506
3507         try {
3508                         QueryCache.runnerTypes(impl, sId, impl.parent, listener, ip);
3509                 } catch (DatabaseException e) {
3510                         Logger.defaultLogError(e);
3511                 }
3512
3513     }
3514     
3515         @Override
3516         final public IntSet getTypes(final ReadGraphImpl impl, final Resource subject) throws Throwable {
3517
3518                 assert(subject != null);
3519                 
3520                 return QueryCacheBase.resultTypes(impl, querySupport.getId(subject), impl.parent, null);
3521
3522         }
3523
3524         @Override
3525         final public RelationInfo getRelationInfo(final ReadGraphImpl impl, final Resource subject) throws DatabaseException {
3526                 
3527                 assert(subject != null);
3528
3529                 return QueryCache.resultRelationInfoQuery(impl, querySupport.getId(subject), impl.parent, null);
3530
3531         }
3532
3533         @Override
3534         final public void forSupertypes(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3535
3536                 assert(subject != null);
3537                 assert(procedure != null);
3538
3539                 final ListenerBase listener = getListenerBase(procedure);
3540
3541                 try {
3542                         QueryCache.runnerSuperTypes(impl, querySupport.getId(subject), impl.parent, listener, new InternalProcedure<IntSet>() {
3543
3544                                 AtomicBoolean first = new AtomicBoolean(true);
3545
3546                                 @Override
3547                                 public void execute(final ReadGraphImpl graph, IntSet set) {
3548 //                              final HashSet<Resource> result = new HashSet<Resource>();
3549 //                              set.forEach(new TIntProcedure() {
3550 //
3551 //                                      @Override
3552 //                                      public boolean execute(int type) {
3553 //                                              result.add(querySupport.getResource(type));
3554 //                                              return true;
3555 //                                      }
3556 //
3557 //                              });
3558                                         try {
3559                                                 if(first.compareAndSet(true, false)) {
3560                                                         procedure.execute(graph, set);
3561 //                                              impl.state.barrier.dec();
3562                                                 } else {
3563                                                         procedure.execute(impl.newRestart(graph), set);
3564                                                 }
3565                                         } catch (Throwable t2) {
3566                                                 Logger.defaultLogError(t2);
3567                                         }
3568                                 }
3569
3570                                 @Override
3571                                 public void exception(ReadGraphImpl graph, Throwable t) {
3572                                         try {
3573                                                 if(first.compareAndSet(true, false)) {
3574                                                         procedure.exception(graph, t);
3575 //                                              impl.state.barrier.dec();
3576                                                 } else {
3577                                                         procedure.exception(impl.newRestart(graph), t);
3578                                                 }
3579                                         } catch (Throwable t2) {
3580                                                 Logger.defaultLogError(t2);
3581                                         }
3582                                 }
3583
3584                         });
3585                 } catch (DatabaseException e) {
3586                         Logger.defaultLogError(e);
3587                 }
3588
3589         }
3590
3591         @Override
3592         final public void forDirectSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3593
3594                 assert(subject != null);
3595                 assert(procedure != null);
3596
3597                 final ListenerBase listener = getListenerBase(procedure);
3598
3599                 IntProcedure ip = new IntProcedureAdapter() {
3600
3601                         @Override
3602                         public void execute(final ReadGraphImpl graph, int superRelation) {
3603                                 try {
3604                                         procedure.execute(graph, querySupport.getResource(superRelation));
3605                                 } catch (Throwable t2) {
3606                                         Logger.defaultLogError(t2);
3607                                 }
3608                         }
3609
3610                         @Override
3611                         public void finished(final ReadGraphImpl graph) {
3612                                 try {
3613                                         procedure.finished(graph);
3614                                 } catch (Throwable t2) {
3615                                         Logger.defaultLogError(t2);
3616                                 }
3617 //                              impl.state.barrier.dec(this);
3618                         }
3619
3620
3621                         @Override
3622                         public void exception(ReadGraphImpl graph, Throwable t) {
3623                                 try {
3624                                         procedure.exception(graph, t);
3625                                 } catch (Throwable t2) {
3626                                         Logger.defaultLogError(t2);
3627                                 }
3628 //                              impl.state.barrier.dec(this);
3629                         }
3630
3631                 };
3632
3633                 int sId = querySupport.getId(subject); 
3634
3635 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectSuperRelations#" + sId);
3636 //              else impl.state.barrier.inc(null, null);
3637
3638                 try {
3639                         QueryCache.runnerDirectSuperRelations(impl, sId, impl.parent, listener, ip);
3640                 } catch (DatabaseException e) {
3641                         Logger.defaultLogError(e);
3642                 }
3643                 
3644 //              DirectSuperRelations.queryEach(impl, sId, this, impl.parent, listener, ip);
3645
3646         }
3647
3648         @Override
3649         final public void forPossibleSuperrelation(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Resource> procedure) {
3650
3651                 assert(subject != null);
3652                 assert(procedure != null);
3653
3654                 final ListenerBase listener = getListenerBase(procedure);
3655
3656 //              impl.state.barrier.inc();
3657
3658                 PossibleSuperRelation.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
3659
3660         }
3661
3662         @Override
3663         final public void forSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3664
3665                 assert(subject != null);
3666                 assert(procedure != null);
3667
3668                 final ListenerBase listener = getListenerBase(procedure);
3669
3670                 InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
3671
3672                         @Override
3673                         public void execute(final ReadGraphImpl graph, IntSet set) {
3674 //                              final HashSet<Resource> result = new HashSet<Resource>();
3675 //                              set.forEach(new TIntProcedure() {
3676 //
3677 //                                      @Override
3678 //                                      public boolean execute(int type) {
3679 //                                              result.add(querySupport.getResource(type));
3680 //                                              return true;
3681 //                                      }
3682 //
3683 //                              });
3684                                 try {
3685                                         procedure.execute(graph, set);
3686                                 } catch (Throwable t2) {
3687                                         Logger.defaultLogError(t2);
3688                                 }
3689 //                              impl.state.barrier.dec(this);
3690                         }
3691
3692                         @Override
3693                         public void exception(ReadGraphImpl graph, Throwable t) {
3694                                 try {
3695                                         procedure.exception(graph, t);
3696                                 } catch (Throwable t2) {
3697                                         Logger.defaultLogError(t2);
3698                                 }
3699 //                              impl.state.barrier.dec(this);
3700                         }
3701
3702                 };
3703
3704                 int sId = querySupport.getId(subject);
3705
3706 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#SuperRelations#" + sId);
3707 //              else impl.state.barrier.inc(null, null);
3708
3709                 try {
3710                         QueryCache.runnerSuperRelations(impl, sId, impl.parent, listener, ip);
3711                 } catch (DatabaseException e) {
3712                         Logger.defaultLogError(e);
3713                 }
3714
3715         }
3716
3717         final public byte[] getValue(final ReadGraphImpl impl, final Resource subject) throws DatabaseException {
3718           return getValue(impl, querySupport.getId(subject));
3719         }
3720
3721         final public byte[] getValue(final ReadGraphImpl impl, final int subject) throws DatabaseException {
3722                 return QueryCache.resultValueQuery(impl, subject, impl.parent, null); 
3723         }
3724
3725         @Override
3726         final public void forValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
3727
3728                 assert(subject != null);
3729                 assert(procedure != null);
3730
3731                 int sId = querySupport.getId(subject);
3732
3733 //              if(procedure != null) {
3734                 
3735                         final ListenerBase listener = getListenerBase(procedure);
3736
3737                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3738
3739                                 AtomicBoolean first = new AtomicBoolean(true);
3740
3741                                 @Override
3742                                 public void execute(ReadGraphImpl graph, byte[] result) {
3743                                         try {
3744                                                 if(first.compareAndSet(true, false)) {
3745                                                         procedure.execute(graph, result);
3746 //                                                      impl.state.barrier.dec(this);
3747                                                 } else {
3748                                                         procedure.execute(impl.newRestart(graph), result);
3749                                                 }
3750                                         } catch (Throwable t2) {
3751                                                 Logger.defaultLogError(t2);
3752                                         }
3753                                 }
3754
3755                                 @Override
3756                                 public void exception(ReadGraphImpl graph, Throwable t) {
3757                                         try {
3758                                                 if(first.compareAndSet(true, false)) {
3759                                                         procedure.exception(graph, t);
3760 //                                                      impl.state.barrier.dec(this);
3761                                                 } else {
3762                                                         procedure.exception(impl.newRestart(graph), t);
3763                                                 }
3764                                         } catch (Throwable t2) {
3765                                                 Logger.defaultLogError(t2);
3766                                         }
3767                                 }
3768
3769                         };
3770
3771 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
3772 //                      else impl.state.barrier.inc(null, null);
3773
3774                         try {
3775                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3776                         } catch (DatabaseException e) {
3777                                 throw new IllegalStateException("Internal error");
3778                         }
3779
3780 //              } else {
3781 //
3782 //                      return QueryCacheBase.runnerValueQuery(impl, sId, impl.parent, null, null);
3783 //                      
3784 //              }
3785 //              
3786 //              throw new IllegalStateException("Internal error");
3787
3788         }
3789
3790         @Override
3791         final public void forPossibleValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
3792
3793                 assert(subject != null);
3794                 assert(procedure != null);
3795
3796                 final ListenerBase listener = getListenerBase(procedure);
3797
3798                 if(impl.parent != null || listener != null) {
3799
3800                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3801
3802                                 AtomicBoolean first = new AtomicBoolean(true);
3803
3804                                 @Override
3805                                 public void execute(ReadGraphImpl graph, byte[] result) {
3806                                         try {
3807                                                 if(first.compareAndSet(true, false)) {
3808                                                         procedure.execute(graph, result);
3809 //                                                      impl.state.barrier.dec(this);
3810                                                 } else {
3811                                                         procedure.execute(impl.newRestart(graph), result);
3812                                                 }
3813                                         } catch (Throwable t2) {
3814                                                 Logger.defaultLogError(t2);
3815                                         }
3816                                 }
3817
3818                                 @Override
3819                                 public void exception(ReadGraphImpl graph, Throwable t) {
3820                                         try {
3821                                                 if(first.compareAndSet(true, false)) {
3822                                                         procedure.exception(graph, t);
3823 //                                                      impl.state.barrier.dec(this);
3824                                                 } else {
3825                                                         procedure.exception(impl.newRestart(graph), t);
3826                                                 }
3827                                         } catch (Throwable t2) {
3828                                                 Logger.defaultLogError(t2);
3829                                         }
3830                                 }
3831
3832                         };
3833
3834                         int sId = querySupport.getId(subject);
3835
3836 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
3837 //                      else impl.state.barrier.inc(null, null);
3838
3839                         try {
3840                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3841                         } catch (DatabaseException e) {
3842                                 Logger.defaultLogError(e);
3843                         }
3844
3845                 } else {
3846
3847                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3848
3849                                 @Override
3850                                 public void execute(ReadGraphImpl graph, byte[] result) {
3851
3852                                         procedure.execute(graph, result);
3853
3854                                 }
3855
3856                                 @Override
3857                                 public void exception(ReadGraphImpl graph, Throwable t) {
3858
3859                                         procedure.exception(graph, t);
3860
3861                                 }
3862
3863                         };
3864
3865                         int sId = querySupport.getId(subject);
3866
3867                         try {
3868                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3869                         } catch (DatabaseException e) {
3870                                 Logger.defaultLogError(e);
3871                         }
3872
3873                 }
3874
3875         }
3876
3877         @Override
3878         final public void forInverse(final ReadGraphImpl impl, final Resource relation, final AsyncProcedure<Resource> procedure) {
3879
3880                 assert(relation != null);
3881                 assert(procedure != null);
3882
3883                 final ListenerBase listener = getListenerBase(procedure);
3884
3885                 IntProcedure ip = new IntProcedure() {
3886
3887                         private int result = 0;
3888                         
3889                     final AtomicBoolean found = new AtomicBoolean(false);
3890                     final AtomicBoolean done = new AtomicBoolean(false);
3891
3892                         @Override
3893                         public void finished(ReadGraphImpl graph) {
3894                                 
3895                         // Shall fire exactly once!
3896                         if(done.compareAndSet(false, true)) {
3897                                 try {
3898                                         if(result == 0) {
3899                                                         procedure.exception(graph, new NoInverseException(""));
3900 //                                              impl.state.barrier.dec(this);
3901                                         } else {
3902                                                 procedure.execute(graph, querySupport.getResource(result));
3903 //                                              impl.state.barrier.dec(this);
3904                                         }
3905                                 } catch (Throwable t) {
3906                                         Logger.defaultLogError(t);
3907                                 }
3908                         }
3909                         
3910                         }
3911
3912                         @Override
3913                         public void execute(ReadGraphImpl graph, int i) {
3914                                 
3915                                 if(found.compareAndSet(false, true)) {
3916                                         this.result = i;
3917                                 } else {
3918                                         // Shall fire exactly once!
3919                                         if(done.compareAndSet(false, true)) {
3920                                                 try {
3921                                                         procedure.exception(graph, new ManyObjectsForFunctionalRelationException("Multiple items e.g. " + this.result + " and " + result));
3922 //                                                      impl.state.barrier.dec(this);
3923                                                 } catch (Throwable t) {
3924                                                 Logger.defaultLogError(t);
3925                                                 }
3926                                         }
3927                                 }
3928                                 
3929                         }
3930
3931                         @Override
3932                         public void exception(ReadGraphImpl graph, Throwable t) {
3933                                 // Shall fire exactly once!
3934                                 if(done.compareAndSet(false, true)) {
3935                                         try {
3936                                                 procedure.exception(graph, t);
3937 //                                              impl.state.barrier.dec(this);
3938                                         } catch (Throwable t2) {
3939                                         Logger.defaultLogError(t2);
3940                                         }
3941                                 }
3942                         }
3943
3944                 };
3945
3946                 int sId = querySupport.getId(relation);
3947
3948 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectObjects#" + sId);
3949 //              else impl.state.barrier.inc(null, null);
3950
3951                 try {
3952                         QueryCache.runnerObjects(impl, sId, getInverseOf(), impl.parent, listener, ip);
3953                 } catch (DatabaseException e) {
3954                         Logger.defaultLogError(e);
3955                 }
3956
3957         }
3958
3959         @Override
3960         final public void forResource(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
3961
3962                 assert(id != null);
3963                 assert(procedure != null);
3964
3965                 InternalProcedure<Integer> ip = new InternalProcedure<Integer>() {
3966
3967                         @Override
3968                         public void execute(ReadGraphImpl graph, Integer result) {
3969                                 try {
3970                                         procedure.execute(graph, querySupport.getResource(result));
3971                                 } catch (Throwable t2) {
3972                                         Logger.defaultLogError(t2);
3973                                 }
3974 //                              impl.state.barrier.dec(this);
3975                         }   
3976
3977                         @Override
3978                         public void exception(ReadGraphImpl graph, Throwable t) {
3979
3980                                 try {
3981                                         procedure.exception(graph, t);
3982                                 } catch (Throwable t2) {
3983                                         Logger.defaultLogError(t2);
3984                                 }
3985 //                              impl.state.barrier.dec(this);
3986                         }
3987
3988                 };
3989
3990 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "Resource");
3991 //              else impl.state.barrier.inc(null, null);
3992
3993                 forResource(impl, id, impl.parent, ip);
3994
3995         }
3996
3997         @Override
3998         final public void forBuiltin(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
3999
4000                 assert(id != null);
4001                 assert(procedure != null);
4002
4003 //              impl.state.barrier.inc();
4004
4005                 try {
4006                         forBuiltin(impl, id, impl.parent, new InternalProcedure<Integer>() {
4007
4008                                 @Override
4009                                 public void execute(ReadGraphImpl graph, Integer result) {
4010                                         try {
4011                                                 procedure.execute(graph, querySupport.getResource(result)); 
4012                                         } catch (Throwable t2) {
4013                                                 Logger.defaultLogError(t2);
4014                                         }
4015 //                              impl.state.barrier.dec();
4016                                 }   
4017
4018                                 @Override
4019                                 public void exception(ReadGraphImpl graph, Throwable t) {
4020                                         try {
4021                                                 procedure.exception(graph, t);
4022                                         } catch (Throwable t2) {
4023                                                 Logger.defaultLogError(t2);
4024                                         }
4025 //                              impl.state.barrier.dec();
4026                                 }
4027
4028                         });
4029                 } catch (DatabaseException e) {
4030                         Logger.defaultLogError(e);
4031                 }
4032
4033         }
4034
4035         @Override
4036         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
4037
4038                 assert(subject != null);
4039                 assert(procedure != null);
4040
4041                 final ListenerBase listener = getListenerBase(procedure);
4042
4043                 try {
4044                         IntSet result = QueryCache.resultDirectPredicates(impl, querySupport.getId(subject), impl.parent, listener);
4045                         procedure.execute(impl, !result.isEmpty());
4046                 } catch (DatabaseException e) {
4047                         procedure.exception(impl, e);
4048                 }
4049                         
4050         }
4051
4052         @Override
4053         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Boolean> procedure) {
4054
4055                 assert(subject != null);
4056                 assert(predicate != null);
4057                 assert(procedure != null);
4058
4059                 AsyncMultiProcedure<Resource> ip = new AsyncMultiProcedureAdapter<Resource>() {
4060
4061                         boolean found = false;
4062
4063                         @Override
4064                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
4065                                 found = true;
4066                         }
4067
4068                         @Override
4069                         synchronized public void finished(AsyncReadGraph graph) {
4070                                 try {
4071                                         procedure.execute(graph, found);
4072                                 } catch (Throwable t2) {
4073                                         Logger.defaultLogError(t2);
4074                                 }
4075 //                              impl.state.barrier.dec(this);
4076                         }
4077
4078                         @Override
4079                         public void exception(AsyncReadGraph graph, Throwable t) {
4080                                 try {
4081                                         procedure.exception(graph, t);
4082                                 } catch (Throwable t2) {
4083                                         Logger.defaultLogError(t2);
4084                                 }
4085 //                              impl.state.barrier.dec(this);
4086                         }
4087
4088                 };
4089
4090 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#ForEachObject#" + subject + "#" + predicate);
4091 //              else impl.state.barrier.inc(null, null);
4092
4093                 forEachObject(impl, subject, predicate, ip);
4094
4095         }
4096
4097         @Override
4098         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final Resource object, final AsyncProcedure<Boolean> procedure) {
4099
4100                 assert(subject != null);
4101                 assert(predicate != null);
4102                 assert(procedure != null);
4103
4104 //              impl.state.barrier.inc();
4105
4106                 forEachObject(impl, subject, predicate, new AsyncMultiProcedureAdapter<Resource>() {
4107
4108                         boolean found = false;
4109
4110                         @Override
4111                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
4112                                 if(resource.equals(object)) found = true;
4113                         }
4114
4115                         @Override
4116                         synchronized public void finished(AsyncReadGraph graph) {
4117                                 try {
4118                                         procedure.execute(graph, found);
4119                                 } catch (Throwable t2) {
4120                                         Logger.defaultLogError(t2);
4121                                 }
4122 //                              impl.state.barrier.dec();
4123                         }
4124
4125                         @Override
4126                         public void exception(AsyncReadGraph graph, Throwable t) {
4127                                 try {
4128                                         procedure.exception(graph, t);
4129                                 } catch (Throwable t2) {
4130                                         Logger.defaultLogError(t2);
4131                                 }
4132 //                              impl.state.barrier.dec();
4133                         }
4134
4135                 });
4136
4137         }
4138
4139         @Override
4140         final public void forHasValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
4141
4142                 assert(subject != null);
4143                 assert(procedure != null);
4144
4145                 final ListenerBase listener = getListenerBase(procedure);
4146
4147 //              impl.state.barrier.inc();
4148
4149                 try {
4150                         QueryCache.runnerValueQuery(impl, querySupport.getId(subject), impl.parent, listener, new InternalProcedure<byte[]>() {
4151
4152                                 @Override
4153                                 public void execute(ReadGraphImpl graph, byte[] object) {
4154                                         boolean result = object != null;
4155                                         try {
4156                                                 procedure.execute(graph, result);
4157                                         } catch (Throwable t2) {
4158                                                 Logger.defaultLogError(t2);
4159                                         }
4160 //                              impl.state.barrier.dec();
4161                                 }
4162
4163                                 @Override
4164                                 public void exception(ReadGraphImpl graph, Throwable t) {
4165                                         try {
4166                                                 procedure.exception(graph, t);
4167                                         } catch (Throwable t2) {
4168                                                 Logger.defaultLogError(t2);
4169                                         }
4170 //                              impl.state.barrier.dec();
4171                                 }
4172
4173                         });
4174                 } catch (DatabaseException e) {
4175                         Logger.defaultLogError(e);
4176                 }
4177
4178         }
4179
4180         @Override
4181         final public void forOrderedSet(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
4182
4183                 assert(subject != null);
4184                 assert(procedure != null);
4185
4186                 final ListenerBase listener = getListenerBase(procedure);
4187
4188                 try {
4189                         
4190                         QueryCache.runnerOrderedSet(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
4191
4192                                 @Override
4193                                 public void exception(ReadGraphImpl graph, Throwable t) {
4194                                         try {
4195                                                 procedure.exception(graph, t);
4196                                         } catch (Throwable t2) {
4197                                                 Logger.defaultLogError(t2);
4198                                         }
4199 //                              impl.state.barrier.dec();
4200                                 }
4201
4202                                 @Override
4203                                 public void execute(ReadGraphImpl graph, int i) {
4204                                         try {
4205                                                 procedure.execute(graph, querySupport.getResource(i));
4206                                         } catch (Throwable t2) {
4207                                                 Logger.defaultLogError(t2);
4208                                         }
4209                                 }
4210
4211                                 @Override
4212                                 public void finished(ReadGraphImpl graph) {
4213                                         try {
4214                                                 procedure.finished(graph);
4215                                         } catch (Throwable t2) {
4216                                                 Logger.defaultLogError(t2);
4217                                         }
4218 //                              impl.state.barrier.dec();
4219                                 }
4220
4221                         });
4222                 } catch (DatabaseException e) {
4223                         Logger.defaultLogError(e);
4224                 }
4225
4226         }
4227
4228 //      @Override
4229 //      final public <T> void query(final ReadGraphImpl impl, final AsyncRead<T> request, final CacheEntry parent, final AsyncProcedure<T> procedure, ListenerBase listener) throws DatabaseException {
4230 //
4231 //              assert(request != null);
4232 //              assert(procedure != null);
4233 //
4234 //              QueryCache.runnerAsyncReadEntry(impl, request, parent, listener, procedure);
4235 //
4236 //      }
4237
4238 //      @Override
4239 //      final public <T> T tryQuery(final ReadGraphImpl graph, final Read<T> request) throws DatabaseException {
4240 //
4241 //              assert(graph != null);
4242 //              assert(request != null);
4243 //
4244 //              final ReadEntry entry = (ReadEntry)cache.getCached(request);
4245 //              if(entry != null && entry.isReady()) {
4246 //                  return (T)entry.get(graph, this, null);
4247 //              } else {
4248 //                      return request.perform(graph);
4249 //              }
4250 //
4251 //      }
4252
4253 //    final public <T> T tryQuery(final ReadGraphImpl graph, final ExternalRead<T> request) throws DatabaseException {
4254 //
4255 //        assert(graph != null);
4256 //        assert(request != null);
4257 //
4258 //        final ExternalReadEntry<T> entry = cache.externalReadMap.get(request);
4259 //        if(entry != null && entry.isReady()) {
4260 //            if(entry.isExcepted()) {
4261 //                Throwable t = (Throwable)entry.getResult();
4262 //                if(t instanceof DatabaseException) throw (DatabaseException)t;
4263 //                else throw new DatabaseException(t);
4264 //            } else {
4265 //                return (T)entry.getResult();
4266 //            }            
4267 //        } else {
4268 //
4269 //            final DataContainer<T> result = new DataContainer<T>();
4270 //            final DataContainer<Throwable> exception = new DataContainer<Throwable>();
4271 //            
4272 //            request.register(graph, new Listener<T>() {
4273 //                
4274 //                @Override
4275 //                public void exception(Throwable t) {
4276 //                    exception.set(t);
4277 //                }
4278 //
4279 //                @Override
4280 //                public void execute(T t) {
4281 //                    result.set(t);
4282 //                }
4283 //
4284 //                @Override
4285 //                public boolean isDisposed() {
4286 //                    return true;
4287 //                }
4288 //            
4289 //            });
4290 //            
4291 //            Throwable t = exception.get();
4292 //            if(t != null) {
4293 //                if(t instanceof DatabaseException) throw (DatabaseException)t;
4294 //                else throw new DatabaseException(t);
4295 //            }
4296 //            
4297 //            return result.get();
4298 //
4299 //        }
4300 //
4301 //    }
4302         
4303 //      @Override
4304 //      final public <T> void tryQuery(final ReadGraphImpl graph, final AsyncRead<T> request, AsyncProcedure<T> procedure) {
4305 //
4306 //              assert(graph != null);
4307 //              assert(request != null);
4308 //
4309 //              final AsyncReadEntry entry = cache.asyncReadMap.get(request);
4310 //              if(entry != null && entry.isReady()) {
4311 //                      if(entry.isExcepted()) {
4312 //                              procedure.exception(graph, (Throwable)entry.getResult());
4313 //                      } else {
4314 //                              procedure.execute(graph, (T)entry.getResult());
4315 //                      }
4316 //              } else {
4317 //                      request.perform(graph, procedure);
4318 //              }
4319 //
4320 //      }
4321
4322         @Override
4323         final public <T> void query(final ReadGraphImpl impl, final MultiRead<T> request, final CacheEntry parent, final SyncMultiProcedure<T> procedure, ListenerBase listener) {
4324
4325                 assert(request != null);
4326                 assert(procedure != null);
4327
4328                 try {
4329
4330                         queryMultiRead(impl, request, parent, listener, procedure);
4331                         
4332                 } catch (DatabaseException e) {
4333                         
4334                         throw new IllegalStateException(e);
4335                         
4336                 }
4337
4338         }
4339
4340         @Override
4341         final public <T> void query(final ReadGraphImpl impl, final AsyncMultiRead<T> request, final CacheEntry parent, final AsyncMultiProcedure<T> procedure, ListenerBase listener) {
4342
4343                 assert(request != null);
4344                 assert(procedure != null);
4345
4346 //              impl.state.barrier.inc();
4347
4348                 runAsyncMultiRead(impl, request, parent, listener, new AsyncMultiProcedure<T>() {
4349
4350                         public void execute(AsyncReadGraph graph, T result) {
4351
4352                                 try {
4353                                         procedure.execute(graph, result);
4354                                 } catch (Throwable t2) {
4355                                         Logger.defaultLogError(t2);
4356                                 }
4357                         }
4358
4359                         @Override
4360                         public void finished(AsyncReadGraph graph) {
4361
4362                                 try {
4363                                         procedure.finished(graph);
4364                                 } catch (Throwable t2) {
4365                                         Logger.defaultLogError(t2);
4366                                 }
4367
4368 //                              impl.state.barrier.dec();
4369
4370                         }
4371
4372                         @Override
4373                         public String toString() {
4374                                 return procedure.toString();
4375                         }
4376
4377                         @Override
4378                         public void exception(AsyncReadGraph graph, Throwable t) {
4379
4380                                 try {
4381                                         procedure.exception(graph, t);
4382                                 } catch (Throwable t2) {
4383                                         Logger.defaultLogError(t2);
4384                                 }
4385
4386 //                              impl.state.barrier.dec();
4387
4388                         }
4389
4390                 });
4391
4392         }
4393
4394 //      @Override
4395 //      final public <T> void query(final ReadGraphImpl impl, final ExternalRead<T> request, final CacheEntry parent, final Procedure<T> procedure, ListenerBase listener) throws DatabaseException {
4396 //
4397 //              assert(request != null);
4398 //              assert(procedure != null);
4399 //
4400 //              try {
4401 //              
4402 //                      queryPrimitiveRead(impl, request, parent, listener, new AsyncProcedure<T>() {
4403 //      
4404 //                              @Override
4405 //                              public String toString() {
4406 //                                      return procedure.toString();
4407 //                              }
4408 //      
4409 //                              @Override
4410 //                              public void execute(AsyncReadGraph graph, T result) {
4411 //                                      try {
4412 //                                              procedure.execute(result);
4413 //                                      } catch (Throwable t2) {
4414 //                                              Logger.defaultLogError(t2);
4415 //                                      }
4416 //                              }
4417 //
4418 //                              @Override
4419 //                              public void exception(AsyncReadGraph graph, Throwable throwable) {
4420 //                                      try {
4421 //                                              procedure.exception(throwable);
4422 //                                      } catch (Throwable t2) {
4423 //                                              Logger.defaultLogError(t2);
4424 //                                      }
4425 //                              }
4426 //      
4427 //                      });
4428 //                      
4429 //              } catch (DatabaseException e) {
4430 //                      
4431 //                      throw new IllegalStateException(e);
4432 //                      
4433 //              }
4434 //
4435 //      }
4436
4437         @Override
4438         public VirtualGraph getProvider(Resource subject, Resource predicate, Resource object) {
4439                 
4440                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
4441                 
4442         }
4443         
4444         @Override
4445         public VirtualGraph getProvider(Resource subject, Resource predicate) {
4446                 
4447                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate));
4448                 
4449         }
4450
4451         @Override
4452         public VirtualGraph getValueProvider(Resource subject) {
4453                 
4454                 return querySupport.getValueProvider(querySupport.getId(subject));
4455                 
4456         }
4457
4458         public boolean resumeTasks(ReadGraphImpl graph) {
4459
4460                 return querySupport.resume(graph);
4461
4462         }
4463         
4464         public boolean isImmutable(int resourceId) {
4465                 return querySupport.isImmutable(resourceId);
4466         }
4467
4468         public boolean isImmutable(Resource resource) {
4469                 ResourceImpl impl = (ResourceImpl)resource;
4470                 return isImmutable(impl.id);
4471         }
4472         
4473         private Layer0 L0;
4474         
4475         public Layer0 getL0(ReadGraph graph) {
4476                 if(L0 == null) {
4477                         L0 = Layer0.getInstance(graph);
4478                 }
4479                 return L0;
4480         }
4481
4482     public static ThreadLocal<Integer> thread = new ThreadLocal<Integer>() {
4483         protected Integer initialValue() {
4484             return -1;
4485         }
4486     };
4487         
4488 }