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