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