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