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