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