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