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