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