]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java
AsyncBarrier.dec runs into refcounting problem
[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                 // Make sure that listening has performed its work
1434                 listening.sync();
1435
1436                 cache.dirty = false;
1437                 lastInvalidate = 0;
1438
1439                 if (Development.DEVELOPMENT) {
1440                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1441                                 System.err.println("== Query update ==");
1442                         }
1443                 }
1444
1445                 // Special case - one statement
1446                 if(scheduledObjectUpdates.size() == 1 && scheduledValueUpdates.size() == 0 && scheduledPrimitiveUpdates.size() == 0 && scheduledInvalidates.size() == 0) {
1447
1448                         long arg0 = scheduledObjectUpdates.getFirst();
1449
1450                         final int subject = (int)(arg0 >>> 32);
1451                         final int predicate = (int)(arg0 & 0xffffffff);
1452
1453                         for(Objects o : QueryCache.entriesObjects(QueryProcessor.this, subject)) markForUpdate(graph, o);
1454                         for(DirectObjects o : QueryCache.entriesDirectObjects(QueryProcessor.this, subject)) markForUpdate(graph, o);
1455                         for(Statements o : QueryCache.entriesStatements(QueryProcessor.this, subject)) markForUpdate(graph, o);
1456
1457                         if(predicate == instanceOf || predicate == inherits || predicate == subrelationOf) {
1458                                 PrincipalTypes principalTypes = QueryCache.entryPrincipalTypes(QueryProcessor.this, subject);
1459                                 if(principalTypes != null) markForUpdate(graph, principalTypes);
1460                                 Types types = QueryCache.entryTypes(QueryProcessor.this, subject);
1461                                 if(types != null) markForUpdate(graph, types);
1462                         }
1463
1464                         if(predicate == subrelationOf) {
1465                                 SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, subject);
1466                                 if(superRelations != null) markForUpdate(graph, superRelations);
1467                         }
1468
1469                         DirectPredicates dp = QueryCache.entryDirectPredicates(QueryProcessor.this, subject);
1470                         if(dp != null) markForUpdate(graph, dp);
1471                         OrderedSet os = QueryCache.entryOrderedSet(QueryProcessor.this, predicate);
1472                         if(os != null) markForUpdate(graph, os);
1473
1474                         updateRefutations(graph);
1475                         
1476                         scheduledObjectUpdates.clear();
1477
1478                         if (Development.DEVELOPMENT) {
1479                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1480                                         System.err.println("== Query update ends ==");
1481                                 }
1482                         }
1483
1484                         return;
1485
1486                 }
1487
1488                 // Special case - one value
1489                 if(scheduledObjectUpdates.size() == 0 && scheduledValueUpdates.size() == 1 && scheduledPrimitiveUpdates.size() == 0 && scheduledInvalidates.size() == 0) {
1490
1491                         int arg0 = scheduledValueUpdates.getFirst();
1492
1493                         ValueQuery valueQuery = QueryCache.entryValueQuery(QueryProcessor.this, arg0);
1494                         if(valueQuery != null) markForUpdate(graph, valueQuery);
1495
1496                         updateRefutations(graph);
1497
1498                         scheduledValueUpdates.clear();
1499
1500                         if (Development.DEVELOPMENT) {
1501                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1502                                         System.err.println("== Query update ends ==");
1503                                 }
1504                         }
1505                         
1506                         return;
1507
1508                 }
1509
1510                 final TIntHashSet predicates = new TIntHashSet();
1511                 final TIntHashSet orderedSets = new TIntHashSet();
1512
1513                 THashSet primitiveUpdates;
1514                 synchronized (primitiveUpdateLock) {
1515                         primitiveUpdates = scheduledPrimitiveUpdates;
1516                         scheduledPrimitiveUpdates = new THashSet();
1517                 }
1518
1519                 scheduledValueUpdates.forEach(new TIntProcedure() {
1520
1521                         @Override
1522                         public boolean execute(int arg0) {
1523                                 ValueQuery valueQuery = QueryCache.entryValueQuery(QueryProcessor.this, arg0);
1524                                 if(valueQuery != null) markForUpdate(graph, valueQuery);
1525                                 return true;
1526                         }
1527
1528                 });
1529
1530                 scheduledInvalidates.forEach(new TIntProcedure() {
1531
1532                         @Override
1533                         public boolean execute(int resource) {
1534                                 
1535                                 ValueQuery valueQuery = QueryCache.entryValueQuery(QueryProcessor.this, resource);
1536                                 if(valueQuery != null) markForUpdate(graph, valueQuery);
1537                                 
1538                                 PrincipalTypes principalTypes = QueryCache.entryPrincipalTypes(QueryProcessor.this, resource);
1539                                 if(principalTypes != null) markForUpdate(graph, principalTypes);
1540                                 Types types = QueryCache.entryTypes(QueryProcessor.this, resource);
1541                                 if(types != null) markForUpdate(graph, types);
1542
1543                                 SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, resource);
1544                                 if(superRelations != null) markForUpdate(graph, superRelations);
1545
1546                                 predicates.add(resource);
1547                                 
1548                                 return true;
1549                         }
1550
1551                 });
1552
1553                 scheduledObjectUpdates.forEach(new TLongProcedure() {
1554
1555                         @Override
1556                         public boolean execute(long arg0) {
1557
1558                                 final int subject = (int)(arg0 >>> 32);
1559                                 final int predicate = (int)(arg0 & 0xffffffff);
1560
1561                                 if(predicate == instanceOf || predicate == inherits || predicate == subrelationOf) {
1562                                         PrincipalTypes principalTypes = QueryCache.entryPrincipalTypes(QueryProcessor.this, subject);
1563                                         if(principalTypes != null) markForUpdate(graph, principalTypes);
1564                                         Types types = QueryCache.entryTypes(QueryProcessor.this, subject);
1565                                         if(types != null) markForUpdate(graph, types);
1566                                 }
1567
1568                                 if(predicate == subrelationOf) {
1569                                         SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, subject);
1570                                         if(superRelations != null) markForUpdate(graph, superRelations);
1571                                 }
1572
1573                                 predicates.add(subject);
1574                                 orderedSets.add(predicate);
1575
1576                                 return true;
1577
1578                         }
1579
1580                 });
1581
1582                 predicates.forEach(new TIntProcedure() {
1583
1584                         @Override
1585                         public boolean execute(final int subject) {
1586
1587                                 for(Objects o : QueryCache.entriesObjects(QueryProcessor.this, subject)) markForUpdate(graph, o);
1588                                 for(DirectObjects o : QueryCache.entriesDirectObjects(QueryProcessor.this, subject)) markForUpdate(graph, o);
1589                                 for(Statements o : QueryCache.entriesStatements(QueryProcessor.this, subject)) markForUpdate(graph, o);
1590
1591                                 DirectPredicates entry = QueryCache.entryDirectPredicates(QueryProcessor.this, subject);
1592                                 if(entry != null) markForUpdate(graph, entry);
1593
1594                                 return true;
1595
1596                         }
1597
1598                 });
1599
1600                 orderedSets.forEach(new TIntProcedure() {
1601
1602                         @Override
1603                         public boolean execute(int orderedSet) {
1604
1605                                 OrderedSet entry = QueryCache.entryOrderedSet(QueryProcessor.this, orderedSet);
1606                                 if(entry != null) markForUpdate(graph, entry);
1607
1608                                 return true;
1609
1610                         }
1611
1612                 });
1613
1614                 updateRefutations(graph);
1615
1616                 primitiveUpdates.forEach(new TObjectProcedure() {
1617
1618                         @Override
1619                         public boolean execute(Object arg0) {
1620
1621                                 ExternalReadEntry query = (ExternalReadEntry)cache.externalReadEntryMap.get(arg0);
1622                                 if (query != null) {
1623                                         boolean listening = update(graph, query);
1624                                         if (!listening && !query.hasParents()) {
1625                                                 cache.externalReadEntryMap.remove(arg0);
1626                                                 query.discard();
1627                                         }
1628                                 }
1629                                 return true;
1630                         }
1631
1632                 });
1633                 
1634                 scheduledValueUpdates.clear();
1635                 scheduledObjectUpdates.clear();
1636                 scheduledInvalidates.clear();
1637                 
1638                 if (Development.DEVELOPMENT) {
1639                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
1640                                 System.err.println("== Query update ends ==");
1641                         }
1642                 }
1643
1644         }
1645
1646         public void updateValue(final int resource) {
1647                 scheduledValueUpdates.add(resource);
1648                 cache.dirty = true;
1649         }
1650
1651         public void updateStatements(final int resource, final int predicate) {
1652                 scheduledObjectUpdates.add((((long)resource) << 32) + predicate);
1653                 cache.dirty = true;
1654         }
1655         
1656         private int lastInvalidate = 0;
1657         
1658         public void invalidateResource(final int resource) {
1659                 if(lastInvalidate == resource) return;
1660                 scheduledValueUpdates.add(resource);
1661                 lastInvalidate = resource;
1662                 cache.dirty = true;
1663         }
1664
1665         public void updatePrimitive(final ExternalRead primitive) {
1666
1667                 // External reads may be updated from arbitrary threads.
1668                 // Synchronize to prevent race-conditions.
1669                 synchronized (primitiveUpdateLock) {
1670                         scheduledPrimitiveUpdates.add(primitive);
1671                 }
1672                 querySupport.dirtyPrimitives();
1673
1674         }
1675
1676         @Override
1677         public synchronized String toString() {
1678                 return "QueryProvider [size = " + cache.size + ", hits = " + cache.hits + " misses = " + cache.misses + ", updates = " + cache.updates + "]";
1679         }
1680
1681         @Override
1682         protected void doDispose() {
1683
1684                 requests.release(Integer.MAX_VALUE / 2);
1685                 
1686                 for(int index = 0; index < THREADS; index++) { 
1687                         executors[index].dispose();
1688                 }
1689
1690                 // First just wait
1691                 for(int i=0;i<100;i++) {
1692
1693                         boolean alive = false;
1694                         for(int index = 0; index < THREADS; index++) { 
1695                                 alive |= executors[index].isAlive();
1696                         }
1697                         if(!alive) return;
1698                         try {
1699                                 Thread.sleep(5);
1700                         } catch (InterruptedException e) {
1701                                 Logger.defaultLogError(e);
1702                         }
1703
1704                 }
1705
1706                 // Then start interrupting
1707                 for(int i=0;i<100;i++) {
1708
1709                         boolean alive = false;
1710                         for(int index = 0; index < THREADS; index++) { 
1711                                 alive |= executors[index].isAlive();
1712                         }
1713                         if(!alive) return;
1714                         for(int index = 0; index < THREADS; index++) {
1715                                 executors[index].interrupt();
1716                         }
1717                 }
1718
1719                 //              // Then just destroy
1720                 //              for(int index = 0; index < THREADS; index++) {
1721                 //                      executors[index].destroy();
1722                 //              }
1723
1724                 for(int index = 0; index < THREADS; index++) {
1725                         try {
1726                                 executors[index].join(5000);
1727                         } catch (InterruptedException e) {
1728                                 Logger.defaultLogError("QueryThread " + index + " will not die.", e);
1729                         }
1730                         executors[index] = null;
1731                 }
1732
1733         }
1734
1735         public int getHits() {
1736                 return cache.hits;
1737         }
1738
1739         public int getMisses() {
1740                 return cache.misses;
1741         }
1742
1743         public int getSize() {
1744                 return cache.size;
1745         }
1746
1747         public Set<Long> getReferencedClusters() {
1748                 HashSet<Long> result = new HashSet<Long>();
1749                 for (CacheEntry entry : QueryCache.entriesObjects(this)) {
1750                         Objects query = (Objects) entry.getQuery();
1751                         result.add(querySupport.getClusterId(query.r1()));
1752                 }
1753                 for (CacheEntry entry : QueryCache.entriesDirectPredicates(this)) {
1754                         DirectPredicates query = (DirectPredicates) entry.getQuery();
1755                         result.add(querySupport.getClusterId(query.id));
1756                 }
1757                 for (CacheEntry entry : cache.valueQueryMap.values()) {
1758                         ValueQuery query = (ValueQuery) entry.getQuery();
1759                         result.add(querySupport.getClusterId(query.id));
1760                 }
1761                 return result;
1762         }
1763
1764         public void assertDone() {
1765         }
1766
1767         CacheCollectionResult allCaches(CacheCollectionResult result) {
1768                 
1769                 return cache.allCaches(result);
1770
1771         }
1772
1773         public void printDiagnostics() {
1774         }
1775
1776         public void requestCluster(ReadGraphImpl graph, long clusterId, Runnable runnable) {
1777                 querySupport.requestCluster(graph, clusterId, runnable);
1778         }
1779
1780         public int clean() {
1781                 collector.collect(0, Integer.MAX_VALUE);
1782                 return cache.size;
1783         }
1784
1785         public void clean(final Collection<ExternalRead<?>> requests) {
1786                 QueryCollectorSupport collectorSupport = new QueryCollectorSupport() {
1787                         Iterator<ExternalRead<?>> iterator = requests.iterator();
1788                         @Override
1789                         public CacheCollectionResult allCaches() {
1790                                 throw new UnsupportedOperationException();
1791                         }
1792                         @Override
1793                         public CacheEntryBase iterate(int level) {
1794                                 if(iterator.hasNext()) {
1795                                         ExternalRead<?> request = iterator.next();
1796                                         ExternalReadEntry entry = cache.externalReadEntryMap.get(request);
1797                                         if (entry != null) return entry;
1798                                         else return iterate(level);
1799                                 } else {
1800                                         iterator = requests.iterator();
1801                                         return null;
1802                                 }
1803                         }
1804                         @Override
1805                         public void remove() {
1806                                 throw new UnsupportedOperationException();
1807                         }
1808                         @Override
1809                         public void setLevel(CacheEntryBase entry, int level) {
1810                                 throw new UnsupportedOperationException();
1811                         }
1812                         @Override
1813                         public Collection<CacheEntry> getRootList() {
1814                                 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>(requests.size());
1815                                 for (ExternalRead<?> request : requests) {
1816                                         ExternalReadEntry entry = cache.externalReadEntryMap.get(request);
1817                                         if (entry != null)
1818                                                 result.add(entry);
1819                                 }
1820                                 return result;
1821                         }
1822                         @Override
1823                         public int getCurrentSize() {
1824                                 return cache.size;
1825                         }
1826                         @Override
1827                         public int calculateCurrentSize() {
1828                                 // This tells the collector to attempt collecting everything.
1829                                 return Integer.MAX_VALUE;
1830                         }
1831                         @Override
1832                         public boolean start(boolean flush) {
1833                                 return true;
1834                         }
1835                 };
1836                 new QueryCollectorImpl2(this, collectorSupport).collect(0, Integer.MAX_VALUE);
1837         }
1838
1839         public void scanPending() {
1840                 
1841                 cache.scanPending();
1842
1843         }
1844
1845         public ReadGraphImpl graphForVirtualRequest() {
1846                 return ReadGraphImpl.createAsync(this);
1847         }
1848
1849         
1850         private HashMap<Resource, Class<?>> builtinValues;
1851         
1852         public Class<?> getBuiltinValue(Resource r) {
1853                 if(builtinValues == null) initBuiltinValues();
1854                 return builtinValues.get(r);
1855         }
1856
1857         Exception callerException = null;
1858
1859     public interface AsyncBarrier {
1860         public void inc(); 
1861         public void dec();
1862         public void waitBarrier(Object request, ReadGraphImpl impl);
1863         public boolean isBlocking();
1864     }
1865
1866 //      final public QueryProcessor processor;
1867 //      final public QuerySupport support;
1868
1869         //    boolean disposed = false;
1870
1871         private void initBuiltinValues() {
1872
1873                 Layer0 b = getSession().peekService(Layer0.class);
1874                 if(b == null) return;
1875
1876                 builtinValues = new HashMap<Resource, Class<?>>();
1877
1878                 builtinValues.put(b.String, String.class);
1879                 builtinValues.put(b.Double, Double.class);
1880                 builtinValues.put(b.Float, Float.class);
1881                 builtinValues.put(b.Long, Long.class);
1882                 builtinValues.put(b.Integer, Integer.class);
1883                 builtinValues.put(b.Byte, Byte.class);
1884                 builtinValues.put(b.Boolean, Boolean.class);
1885
1886                 builtinValues.put(b.StringArray, String[].class);
1887                 builtinValues.put(b.DoubleArray, double[].class);
1888                 builtinValues.put(b.FloatArray, float[].class);
1889                 builtinValues.put(b.LongArray, long[].class);
1890                 builtinValues.put(b.IntegerArray, int[].class);
1891                 builtinValues.put(b.ByteArray, byte[].class);
1892                 builtinValues.put(b.BooleanArray, boolean[].class);
1893
1894         }
1895
1896 //      public ReadGraphSupportImpl(final QueryProcessor provider2) {
1897 //
1898 //              if (null == provider2) {
1899 //                      this.processor = null;
1900 //                      support = null;
1901 //                      return;
1902 //              }
1903 //              this.processor = provider2;
1904 //              support = provider2.getCore();
1905 //              initBuiltinValues();
1906 //
1907 //      }
1908
1909 //      final static public ReadGraphSupportImpl basedOn(ReadGraphSupportImpl impl) {
1910 //              return new ReadGraphSupportImpl(impl.processor);
1911 //      }
1912
1913         @Override
1914         final public Session getSession() {
1915                 return session;
1916         }
1917         
1918         final public ResourceSupport getResourceSupport() {
1919                 return resourceSupport;
1920         }
1921
1922         @Override
1923         final public void forEachPredicate(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
1924
1925         try {
1926
1927                 for(Resource predicate : getPredicates(impl, subject))
1928                     procedure.execute(impl, predicate);
1929
1930                 procedure.finished(impl);
1931
1932             } catch (Throwable e) {
1933                 procedure.exception(impl, e);
1934             }
1935
1936         }
1937
1938         @Override
1939         final public void forEachPredicate(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
1940                 
1941                 throw new UnsupportedOperationException();
1942
1943 //              assert(subject != null);
1944 //              assert(procedure != null);
1945 //
1946 //              final ListenerBase listener = getListenerBase(procedure);
1947 //
1948 //              try {
1949 //                      QueryCache.runnerPredicates(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
1950 //
1951 //                              @Override
1952 //                              public void execute(ReadGraphImpl graph, int i) {
1953 //                                      try {
1954 //                                              procedure.execute(querySupport.getResource(i));
1955 //                                      } catch (Throwable t2) {
1956 //                                              Logger.defaultLogError(t2);
1957 //                                      }
1958 //                              }
1959 //
1960 //                              @Override
1961 //                              public void finished(ReadGraphImpl graph) {
1962 //                                      try {
1963 //                                              procedure.finished();
1964 //                                      } catch (Throwable t2) {
1965 //                                              Logger.defaultLogError(t2);
1966 //                                      }
1967 ////                            impl.state.barrier.dec();
1968 //                              }
1969 //
1970 //                              @Override
1971 //                              public void exception(ReadGraphImpl graph, Throwable t) {
1972 //                                      try {
1973 //                                              procedure.exception(t);
1974 //                                      } catch (Throwable t2) {
1975 //                                              Logger.defaultLogError(t2);
1976 //                                      }
1977 ////                            impl.state.barrier.dec();
1978 //                              }
1979 //
1980 //                      });
1981 //              } catch (DatabaseException e) {
1982 //                      Logger.defaultLogError(e);
1983 //              }
1984
1985         }
1986         
1987         @Override
1988         final public IntSet getPredicates(final ReadGraphImpl impl, final Resource subject) throws Throwable {
1989                 return QueryCacheBase.resultPredicates(impl, querySupport.getId(subject), impl.parent, null); 
1990         }
1991
1992         @Override
1993         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
1994                         final Resource predicate, final MultiProcedure<Statement> procedure) {
1995
1996                 assert(subject != null);
1997                 assert(predicate != null);
1998                 assert(procedure != null);
1999
2000                 final ListenerBase listener = getListenerBase(procedure);
2001
2002 //              impl.state.barrier.inc();
2003
2004                 try {
2005                         Statements.queryEach(impl, querySupport.getId(subject), querySupport.getId(predicate), this, impl.parent, listener, new TripleIntProcedureAdapter() {
2006
2007                                 @Override
2008                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
2009                                         try {
2010                                                 procedure.execute(querySupport.getStatement(s, p, o));
2011                                         } catch (Throwable t2) {
2012                                                 Logger.defaultLogError(t2);
2013                                         }
2014                                 }
2015
2016                                 @Override
2017                                 public void finished(ReadGraphImpl graph) {
2018                                         try {
2019                                                 procedure.finished();
2020                                         } catch (Throwable t2) {
2021                                                 Logger.defaultLogError(t2);
2022                                         }
2023 //                              impl.state.barrier.dec();
2024                                 }
2025
2026                                 @Override
2027                                 public void exception(ReadGraphImpl graph, Throwable t) {
2028                                         try {
2029                                                 procedure.exception(t);
2030                                         } catch (Throwable t2) {
2031                                                 Logger.defaultLogError(t2);
2032                                         }
2033 //                              impl.state.barrier.dec();
2034                                 }
2035
2036                         });
2037                 } catch (DatabaseException e) {
2038                         Logger.defaultLogError(e);
2039                 }
2040
2041         }
2042
2043         @Override
2044         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2045                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
2046
2047                 assert(subject != null);
2048                 assert(predicate != null);
2049                 assert(procedure != null);
2050
2051                 final ListenerBase listener = getListenerBase(procedure);
2052
2053                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
2054
2055                         boolean first = true;
2056
2057                         @Override
2058                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
2059                                 try {
2060                                         if(first) {
2061                                                 procedure.execute(graph, querySupport.getStatement(s, p, o));
2062                                         } else {
2063                                                 procedure.execute(impl.newRestart(graph), querySupport.getStatement(s, p, o));
2064                                         }
2065                                 } catch (Throwable t2) {
2066                                         Logger.defaultLogError(t2);
2067                                 }
2068                         }
2069
2070                         @Override
2071                         public void finished(ReadGraphImpl graph) {
2072
2073                                 try {
2074                                         if(first) {
2075                                                 first = false;
2076                                                 procedure.finished(graph);
2077 //                                              impl.state.barrier.dec(this);
2078                                         } else {
2079                                                 procedure.finished(impl.newRestart(graph));
2080                                         }
2081                                 } catch (Throwable t2) {
2082                                         Logger.defaultLogError(t2);
2083                                 }
2084
2085                         }
2086
2087                         @Override
2088                         public void exception(ReadGraphImpl graph, Throwable t) {
2089
2090                                 try {
2091                                         if(first) {
2092                                                 first = false;
2093                                                 procedure.exception(graph, t);
2094 //                                              impl.state.barrier.dec(this);
2095                                         } else {
2096                                                 procedure.exception(impl.newRestart(graph), t);
2097                                         }
2098                                 } catch (Throwable t2) {
2099                                         Logger.defaultLogError(t2);
2100                                 }
2101
2102                         }
2103
2104                 };
2105
2106                 int sId = querySupport.getId(subject);
2107                 int pId = querySupport.getId(predicate);
2108
2109 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
2110 //              else impl.state.barrier.inc(null, null);
2111
2112                 try {
2113                         Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
2114                 } catch (DatabaseException e) {
2115                         Logger.defaultLogError(e);
2116                 }
2117
2118         }
2119
2120         @Override
2121         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
2122                         final Resource predicate, final StatementProcedure procedure) {
2123
2124                 assert(subject != null);
2125                 assert(predicate != null);
2126                 assert(procedure != null);
2127
2128                 final ListenerBase listener = getListenerBase(procedure);
2129
2130                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
2131
2132                         boolean first = true;
2133
2134                         @Override
2135                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
2136                                 try {
2137                                         if(first) {
2138                                                 procedure.execute(graph, s, p, o);
2139                                         } else {
2140                                                 procedure.execute(impl.newRestart(graph), s, p, o);
2141                                         }
2142                                 } catch (Throwable t2) {
2143                                         Logger.defaultLogError(t2);
2144                                 }
2145                         }
2146
2147                         @Override
2148                         public void finished(ReadGraphImpl graph) {
2149
2150                                 try {
2151                                         if(first) {
2152                                                 first = false;
2153                                                 procedure.finished(graph);
2154 //                                              impl.state.barrier.dec(this);
2155                                         } else {
2156                                                 procedure.finished(impl.newRestart(graph));
2157                                         }
2158                                 } catch (Throwable t2) {
2159                                         Logger.defaultLogError(t2);
2160                                 }
2161
2162                         }
2163
2164                         @Override
2165                         public void exception(ReadGraphImpl graph, Throwable t) {
2166
2167                                 try {
2168                                         if(first) {
2169                                                 first = false;
2170                                                 procedure.exception(graph, t);
2171 //                                              impl.state.barrier.dec(this);
2172                                         } else {
2173                                                 procedure.exception(impl.newRestart(graph), t);
2174                                         }
2175                                 } catch (Throwable t2) {
2176                                         Logger.defaultLogError(t2);
2177                                 }
2178
2179                         }
2180
2181                 };
2182
2183                 int sId = querySupport.getId(subject);
2184                 int pId = querySupport.getId(predicate);
2185
2186 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
2187 //              else impl.state.barrier.inc(null, null);
2188
2189                 try {
2190                         Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
2191                 } catch (DatabaseException e) {
2192                         Logger.defaultLogError(e);
2193                 }
2194
2195         }
2196         
2197         @Override
2198         final public void forStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
2199
2200                 assert(subject != null);
2201                 assert(predicate != null);
2202                 assert(procedure != null);
2203
2204                 forEachStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
2205
2206                         private Set<Statement> current = null;
2207                         private Set<Statement> run = new HashSet<Statement>();
2208
2209                         @Override
2210                         public void execute(AsyncReadGraph graph, Statement result) {
2211
2212                                 boolean found = false;
2213
2214                                 if(current != null) {
2215
2216                                         found = current.remove(result);
2217
2218                                 }
2219
2220                                 if(!found) procedure.add(graph, result);
2221
2222                                 run.add(result);
2223
2224                         }
2225
2226                         @Override
2227                         public void finished(AsyncReadGraph graph) {
2228
2229                                 if(current != null) { 
2230                                         for(Statement r : current) procedure.remove(graph, r);
2231                                 }
2232
2233                                 current = run;
2234
2235                                 run = new HashSet<Statement>();
2236
2237                         }
2238
2239                         @Override
2240                         public void exception(AsyncReadGraph graph, Throwable t) {
2241                                 procedure.exception(graph, t);
2242                         }
2243
2244                         @Override
2245                         public boolean isDisposed() {
2246                                 return procedure.isDisposed();
2247                         }
2248
2249                 });
2250
2251         }
2252
2253         @Override
2254         final public void forEachAssertedStatement(final ReadGraphImpl impl, final Resource subject,
2255                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
2256
2257                 assert(subject != null);
2258                 assert(predicate != null);
2259                 assert(procedure != null);
2260
2261                 final ListenerBase listener = getListenerBase(procedure);
2262
2263 //              impl.state.barrier.inc();
2264
2265                 try {
2266                         QueryCache.runnerAssertedStatements(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new TripleIntProcedureAdapter() {
2267
2268                                 @Override
2269                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
2270                                         try {
2271                                                 procedure.execute(graph, querySupport.getStatement(s, p, o));
2272                                         } catch (Throwable t2) {
2273                                                 Logger.defaultLogError(t2);
2274                                         }
2275                                 }
2276
2277                                 @Override
2278                                 public void finished(ReadGraphImpl graph) {
2279                                         try {
2280                                                 procedure.finished(graph);
2281                                         } catch (Throwable t2) {
2282                                                 Logger.defaultLogError(t2);
2283                                         }
2284 //                              impl.state.barrier.dec();
2285                                 }
2286
2287                                 @Override
2288                                 public void exception(ReadGraphImpl graph, Throwable t) {
2289                                         try {
2290                                                 procedure.exception(graph, t);
2291                                         } catch (Throwable t2) {
2292                                                 Logger.defaultLogError(t2);
2293                                         }
2294 //                              impl.state.barrier.dec();
2295                                 }
2296
2297                         });
2298                 } catch (DatabaseException e) {
2299                         Logger.defaultLogError(e);
2300                 }
2301
2302         }
2303
2304         private static ListenerBase getListenerBase(Object procedure) {
2305                 if(procedure instanceof ListenerBase) return (ListenerBase)procedure;
2306                 else return null;
2307         }
2308
2309         @Override
2310         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final MultiProcedure<Resource> procedure) {
2311
2312                 assert(subject != null);
2313                 assert(predicate != null);
2314                 assert(procedure != null);
2315
2316                 final ListenerBase listener = getListenerBase(procedure);
2317
2318 //              impl.state.barrier.inc();
2319
2320                 try {
2321                         QueryCache.runnerObjects(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new IntProcedure() {
2322
2323                                 @Override
2324                                 public void execute(ReadGraphImpl graph, int i) {
2325                                         try {
2326                                                 procedure.execute(querySupport.getResource(i));
2327                                         } catch (Throwable t2) {
2328                                                 Logger.defaultLogError(t2);
2329                                         }
2330                                 }
2331
2332                                 @Override
2333                                 public void finished(ReadGraphImpl graph) {
2334                                         try {
2335                                                 procedure.finished();
2336                                         } catch (Throwable t2) {
2337                                                 Logger.defaultLogError(t2);
2338                                         }
2339 //                              impl.state.barrier.dec();
2340                                 }
2341
2342                                 @Override
2343                                 public void exception(ReadGraphImpl graph, Throwable t) {
2344                                         System.out.println("forEachObject exception " + t);
2345                                         try {
2346                                                 procedure.exception(t);
2347                                         } catch (Throwable t2) {
2348                                                 Logger.defaultLogError(t2);
2349                                         }
2350 //                              impl.state.barrier.dec();
2351                                 }
2352
2353                         });
2354                 } catch (DatabaseException e) {
2355                         Logger.defaultLogError(e);
2356                 }
2357
2358         }
2359
2360         @Override
2361         final public void forEachDirectPredicate(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
2362
2363                 assert(subject != null);
2364                 assert(procedure != null);
2365
2366                 final ListenerBase listener = getListenerBase(procedure);
2367
2368                 int sId = querySupport.getId(subject);
2369
2370                 try {
2371                         QueryCache.runnerDirectPredicates(impl, sId, impl.parent, listener, new InternalProcedure<IntSet>() {
2372
2373                                 @Override
2374                                 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
2375                                         procedure.execute(graph, result);
2376                                 }
2377
2378                                 @Override
2379                                 public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
2380                                         procedure.exception(graph, throwable);
2381                                 }
2382                                 
2383                         });
2384                 } catch (DatabaseException e) {
2385                         Logger.defaultLogError(e);
2386                 }
2387
2388         }
2389
2390         final public DirectStatements getDirectStatements(final ReadGraphImpl impl, final Resource subject, final boolean ignoreVirtual) {
2391
2392 //              assert(subject != null);
2393 //              assert(procedure != null);
2394 //
2395 //              final ListenerBase listener = getListenerBase(procedure);
2396 //
2397 //              org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
2398                 
2399                 return querySupport.getStatements(impl, querySupport.getId(subject), this, ignoreVirtual);
2400
2401         }
2402
2403 //      @Override
2404 //      final public void forEachDirectStatement(final ReadGraphImpl impl, final Resource subject, final SyncProcedure<DirectStatements> procedure, boolean ignoreVirtual) {
2405 //
2406 //              assert(subject != null);
2407 //              assert(procedure != null);
2408 //
2409 //              final ListenerBase listener = getListenerBase(procedure);
2410 //
2411 //              org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure, ignoreVirtual);
2412 //
2413 //      }
2414         
2415         private static final Resource INVALID_RESOURCE = new ResourceImpl(null, Integer.MIN_VALUE);
2416
2417         @Override
2418         final public void forPossibleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Resource> procedure) {
2419
2420                 forEachObject(impl, subject, predicate, new AsyncMultiProcedure<Resource>() {
2421
2422                         private Resource single = null;
2423
2424                         @Override
2425                         public synchronized void execute(AsyncReadGraph graph, Resource result) {
2426                                 if(single == null) {
2427                                         single = result;
2428                                 } else {
2429                                         single = INVALID_RESOURCE;
2430                                 }
2431                         }
2432
2433                         @Override
2434                         public synchronized void finished(AsyncReadGraph graph) {
2435                                 if(single == null || single == INVALID_RESOURCE) procedure.execute(graph, null);
2436                                 else procedure.execute(graph, single);
2437                         }
2438
2439                         @Override
2440                         public synchronized void exception(AsyncReadGraph graph, Throwable throwable) {
2441                                 procedure.exception(graph, throwable);
2442                         }
2443
2444                 });
2445
2446         }
2447
2448         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final ListenerBase listener, final IntProcedure procedure) {
2449                 
2450                 final int sId = querySupport.getId(subject);
2451                 final int pId = querySupport.getId(predicate);
2452
2453                 try {
2454                         QueryCache.runnerObjects(impl, sId, pId, impl.parent, listener, procedure);
2455                 } catch (DatabaseException e) {
2456                         Logger.defaultLogError(e);
2457                 }
2458                 
2459         }
2460         
2461         static class Runner2Procedure implements IntProcedure {
2462             
2463             public int single = 0;
2464             public Throwable t = null;
2465
2466             public void clear() {
2467                 single = 0;
2468                 t = null;
2469             }
2470             
2471         @Override
2472         public void execute(ReadGraphImpl graph, int i) {
2473             if(single == 0) single = i;
2474             else single = -1;
2475         }
2476
2477         @Override
2478         public void finished(ReadGraphImpl graph) {
2479             if(single == -1) single = 0;
2480         }
2481
2482         @Override
2483         public void exception(ReadGraphImpl graph, Throwable throwable) {
2484             single = 0;
2485             this.t = throwable;
2486         }
2487         
2488         public int get() throws DatabaseException {
2489             if(t != null) {
2490                 if(t instanceof DatabaseException) throw (DatabaseException)t;
2491                 else throw new DatabaseException(t);
2492             }
2493             return single;
2494         }
2495             
2496         }
2497         
2498         final public int getSingleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate) throws DatabaseException {
2499                 
2500                 final int sId = querySupport.getId(subject);
2501                 final int pId = querySupport.getId(predicate);
2502
2503                 Runner2Procedure proc = new Runner2Procedure();
2504                 QueryCache.runnerObjects(impl, sId, pId, impl.parent, null, proc);
2505                 return proc.get();
2506             
2507         }
2508
2509         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
2510
2511                 assert(subject != null);
2512                 assert(predicate != null);
2513
2514                 final ListenerBase listener = getListenerBase(procedure);
2515
2516                 if(impl.parent != null || listener != null) {
2517
2518                         IntProcedure ip = new IntProcedure() {
2519
2520                                 AtomicBoolean first = new AtomicBoolean(true);
2521
2522                                 @Override
2523                                 public void execute(ReadGraphImpl graph, int i) {
2524                                         try {
2525                                                 if(first.get()) {
2526                                                         procedure.execute(impl, querySupport.getResource(i));
2527                                                 } else {
2528                                                         procedure.execute(impl.newRestart(graph), querySupport.getResource(i));
2529                                                 }
2530                                         } catch (Throwable t2) {
2531                                                 Logger.defaultLogError(t2);
2532                                         }
2533
2534                                 }
2535
2536                                 @Override
2537                                 public void finished(ReadGraphImpl graph) {
2538                                         try {
2539                                                 if(first.compareAndSet(true, false)) {
2540                                                         procedure.finished(impl);
2541 //                                                      impl.state.barrier.dec(this);
2542                                                 } else {
2543                                                         procedure.finished(impl.newRestart(graph));
2544                                                 }
2545                                         } catch (Throwable t2) {
2546                                                 Logger.defaultLogError(t2);
2547                                         }
2548                                 }
2549
2550                                 @Override
2551                                 public void exception(ReadGraphImpl graph, Throwable t) {
2552                                         try {
2553                                                 procedure.exception(graph, t);
2554                                         } catch (Throwable t2) {
2555                                                 Logger.defaultLogError(t2);
2556                                         }
2557 //                                      impl.state.barrier.dec(this);
2558                                 }
2559
2560                                 @Override
2561                                 public String toString() {
2562                                         return "forEachObject with " + procedure;
2563                                 }
2564
2565                         };
2566
2567 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Objects" + subject + "#" + predicate);
2568 //                      else impl.state.barrier.inc(null, null);
2569
2570                         forEachObject(impl, subject, predicate, listener, ip);
2571
2572                 } else {
2573
2574                         IntProcedure ip = new IntProcedure() {
2575
2576                                 @Override
2577                                 public void execute(ReadGraphImpl graph, int i) {
2578                                         procedure.execute(graph, querySupport.getResource(i));
2579                                 }
2580
2581                                 @Override
2582                                 public void finished(ReadGraphImpl graph) {
2583                                         procedure.finished(graph);
2584                                 }
2585
2586                                 @Override
2587                                 public void exception(ReadGraphImpl graph, Throwable t) {
2588                                         procedure.exception(graph, t);
2589                                 }
2590
2591                                 @Override
2592                                 public String toString() {
2593                                         return "forEachObject with " + procedure;
2594                                 }
2595
2596                         };
2597
2598                         forEachObject(impl, subject, predicate, listener, ip);
2599
2600                 }
2601
2602         }
2603
2604         @Override
2605         final public void forObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
2606
2607                 assert(subject != null);
2608                 assert(predicate != null);
2609                 assert(procedure != null);
2610
2611                 forEachObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
2612
2613                         private Set<Resource> current = null;
2614                         private Set<Resource> run = new HashSet<Resource>();
2615
2616                         @Override
2617                         public void execute(AsyncReadGraph graph, Resource result) {
2618
2619                                 boolean found = false;
2620
2621                                 if(current != null) {
2622
2623                                         found = current.remove(result);
2624
2625                                 }
2626
2627                                 if(!found) procedure.add(graph, result);
2628
2629                                 run.add(result);
2630
2631                         }
2632
2633                         @Override
2634                         public void finished(AsyncReadGraph graph) {
2635
2636                                 if(current != null) { 
2637                                         for(Resource r : current) procedure.remove(graph, r);
2638                                 }
2639
2640                                 current = run;
2641
2642                                 run = new HashSet<Resource>();
2643
2644                         }
2645
2646                         @Override
2647                         public boolean isDisposed() {
2648                                 return procedure.isDisposed();
2649                         }
2650
2651                         @Override
2652                         public void exception(AsyncReadGraph graph, Throwable t) {
2653                                 procedure.exception(graph, t);
2654                         }
2655
2656                         @Override
2657                         public String toString() {
2658                                 return "forObjectSet " + procedure;
2659                         }
2660
2661                 });
2662
2663         }
2664
2665         @Override
2666         final public void forPredicateSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
2667
2668                 assert(subject != null);
2669                 assert(procedure != null);
2670
2671                 forEachPredicate(impl, subject, new AsyncMultiListener<Resource>() {
2672
2673                         private Set<Resource> current = null;
2674                         private Set<Resource> run = new HashSet<Resource>();
2675
2676                         @Override
2677                         public void execute(AsyncReadGraph graph, Resource result) {
2678
2679                                 boolean found = false;
2680
2681                                 if(current != null) {
2682
2683                                         found = current.remove(result);
2684
2685                                 }
2686
2687                                 if(!found) procedure.add(graph, result);
2688
2689                                 run.add(result);
2690
2691                         }
2692
2693                         @Override
2694                         public void finished(AsyncReadGraph graph) {
2695
2696                                 if(current != null) { 
2697                                         for(Resource r : current) procedure.remove(graph, r);
2698                                 }
2699
2700                                 current = run;
2701
2702                                 run = new HashSet<Resource>();
2703
2704                         }
2705
2706                         @Override
2707                         public boolean isDisposed() {
2708                                 return procedure.isDisposed();
2709                         }
2710
2711                         @Override
2712                         public void exception(AsyncReadGraph graph, Throwable t) {
2713                                 procedure.exception(graph, t);
2714                         }
2715
2716                         @Override
2717                         public String toString() {
2718                                 return "forPredicateSet " + procedure;
2719                         }
2720
2721                 });
2722
2723         }
2724
2725         @Override
2726         final public void forPrincipalTypeSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
2727
2728                 assert(subject != null);
2729                 assert(procedure != null);
2730
2731                 forEachPrincipalType(impl, subject, new AsyncMultiListener<Resource>() {
2732
2733                         private Set<Resource> current = null;
2734                         private Set<Resource> run = new HashSet<Resource>();
2735
2736                         @Override
2737                         public void execute(AsyncReadGraph graph, Resource result) {
2738
2739                                 boolean found = false;
2740
2741                                 if(current != null) {
2742
2743                                         found = current.remove(result);
2744
2745                                 }
2746
2747                                 if(!found) procedure.add(graph, result);
2748
2749                                 run.add(result);
2750
2751                         }
2752
2753                         @Override
2754                         public void finished(AsyncReadGraph graph) {
2755
2756                                 if(current != null) { 
2757                                         for(Resource r : current) procedure.remove(graph, r);
2758                                 }
2759
2760                                 current = run;
2761
2762                                 run = new HashSet<Resource>();
2763
2764                         }
2765
2766                         @Override
2767                         public boolean isDisposed() {
2768                                 return procedure.isDisposed();
2769                         }
2770
2771                         @Override
2772                         public void exception(AsyncReadGraph graph, Throwable t) {
2773                                 procedure.exception(graph, t);
2774                         }
2775
2776                         @Override
2777                         public String toString() {
2778                                 return "forPrincipalTypeSet " + procedure;
2779                         }
2780
2781                 });
2782
2783         }
2784
2785         @Override
2786         final public void forAssertedObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
2787
2788                 assert(subject != null);
2789                 assert(predicate != null);
2790                 assert(procedure != null);
2791
2792                 forEachAssertedObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
2793
2794                         private Set<Resource> current = null;
2795                         private Set<Resource> run = new HashSet<Resource>();
2796
2797                         @Override
2798                         public void execute(AsyncReadGraph graph, Resource result) {
2799
2800                                 boolean found = false;
2801
2802                                 if(current != null) {
2803
2804                                         found = current.remove(result);
2805
2806                                 }
2807
2808                                 if(!found) procedure.add(graph, result);
2809
2810                                 run.add(result);
2811
2812                         }
2813
2814                         @Override
2815                         public void finished(AsyncReadGraph graph) {
2816
2817                                 if(current != null) { 
2818                                         for(Resource r : current) procedure.remove(graph, r);
2819                                 }
2820
2821                                 current = run;
2822
2823                                 run = new HashSet<Resource>();
2824
2825                         }
2826
2827                         @Override
2828                         public boolean isDisposed() {
2829                                 return procedure.isDisposed();
2830                         }
2831
2832                         @Override
2833                         public void exception(AsyncReadGraph graph, Throwable t) {
2834                                 procedure.exception(graph, t);
2835                         }
2836
2837                         @Override
2838                         public String toString() {
2839                                 return "forObjectSet " + procedure;
2840                         }
2841
2842                 });
2843
2844         }
2845
2846         @Override
2847         final public void forAssertedStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
2848
2849                 assert(subject != null);
2850                 assert(predicate != null);
2851                 assert(procedure != null);
2852
2853                 forEachAssertedStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
2854
2855                         private Set<Statement> current = null;
2856                         private Set<Statement> run = new HashSet<Statement>();
2857
2858                         @Override
2859                         public void execute(AsyncReadGraph graph, Statement result) {
2860
2861                                 boolean found = false;
2862
2863                                 if(current != null) {
2864
2865                                         found = current.remove(result);
2866
2867                                 }
2868
2869                                 if(!found) procedure.add(graph, result);
2870
2871                                 run.add(result);
2872
2873                         }
2874
2875                         @Override
2876                         public void finished(AsyncReadGraph graph) {
2877
2878                                 if(current != null) { 
2879                                         for(Statement s : current) procedure.remove(graph, s);
2880                                 }
2881
2882                                 current = run;
2883
2884                                 run = new HashSet<Statement>();
2885
2886                         }
2887
2888                         @Override
2889                         public boolean isDisposed() {
2890                                 return procedure.isDisposed();
2891                         }
2892
2893                         @Override
2894                         public void exception(AsyncReadGraph graph, Throwable t) {
2895                                 procedure.exception(graph, t);
2896                         }
2897
2898                         @Override
2899                         public String toString() {
2900                                 return "forStatementSet " + procedure;
2901                         }
2902
2903                 });
2904
2905         }
2906
2907         @Override
2908         final public void forEachAssertedObject(final ReadGraphImpl impl, final Resource subject,
2909                         final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
2910
2911                 assert(subject != null);
2912                 assert(predicate != null);
2913                 assert(procedure != null);
2914
2915                 final ListenerBase listener = getListenerBase(procedure);
2916
2917                 try {
2918                         QueryCache.runnerAssertedStatements(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new TripleIntProcedure() {
2919
2920                                 @Override
2921                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
2922                                         try {
2923                                                 procedure.execute(graph, querySupport.getResource(o));
2924                                         } catch (Throwable t2) {
2925                                                 Logger.defaultLogError(t2);
2926                                         }
2927                                 }
2928
2929                                 @Override
2930                                 public void finished(ReadGraphImpl graph) {
2931                                         try {               
2932                                                 procedure.finished(graph);
2933                                         } catch (Throwable t2) {
2934                                                 Logger.defaultLogError(t2);
2935                                         }
2936 //                              impl.state.barrier.dec();
2937                                 }
2938
2939                                 @Override
2940                                 public void exception(ReadGraphImpl graph, Throwable t) {
2941                                         try {
2942                                                 procedure.exception(graph, t);
2943                                         } catch (Throwable t2) {
2944                                                 Logger.defaultLogError(t2);
2945                                         }
2946 //                              impl.state.barrier.dec();
2947                                 }
2948
2949                         });
2950                 } catch (DatabaseException e) {
2951                         Logger.defaultLogError(e);
2952                 }
2953
2954         }
2955
2956         @Override
2957         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
2958
2959                 assert(subject != null);
2960                 assert(procedure != null);
2961
2962                 final ListenerBase listener = getListenerBase(procedure);
2963
2964                 IntProcedure ip = new IntProcedure() {
2965
2966                         @Override
2967                         public void execute(ReadGraphImpl graph, int i) {
2968                                 try {
2969                                         procedure.execute(graph, querySupport.getResource(i));
2970                                 } catch (Throwable t2) {
2971                                         Logger.defaultLogError(t2);
2972                                 }
2973                         }
2974
2975                         @Override
2976                         public void finished(ReadGraphImpl graph) {
2977                                 try {
2978                                         procedure.finished(graph);
2979                                 } catch (Throwable t2) {
2980                                         Logger.defaultLogError(t2);
2981                                 }
2982 //                              impl.state.barrier.dec(this);
2983                         }
2984
2985                         @Override
2986                         public void exception(ReadGraphImpl graph, Throwable t) {
2987                                 try {
2988                                         procedure.exception(graph, t);
2989                                 } catch (Throwable t2) {
2990                                         Logger.defaultLogError(t2);
2991                                 }
2992 //                              impl.state.barrier.dec(this);
2993                         }
2994
2995                 };
2996
2997                 int sId = querySupport.getId(subject);
2998
2999 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#PrincipalTypes#" + sId);
3000 //              else impl.state.barrier.inc(null, null);
3001
3002                 try {
3003                         QueryCache.runnerPrincipalTypes(impl, sId, impl.parent, listener, ip);
3004                 } catch (DatabaseException e) {
3005                         Logger.defaultLogError(e);
3006                 }
3007
3008         }
3009
3010         @Override
3011         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
3012
3013                 assert(subject != null);
3014                 assert(procedure != null);
3015
3016                 final ListenerBase listener = getListenerBase(procedure);
3017
3018 //              impl.state.barrier.inc();
3019
3020                 try {
3021                         QueryCache.runnerPrincipalTypes(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
3022
3023                                 @Override
3024                                 public void execute(ReadGraphImpl graph, int i) {
3025                                         try {
3026                                                 procedure.execute(querySupport.getResource(i));
3027                                         } catch (Throwable t2) {
3028                                                 Logger.defaultLogError(t2);
3029                                         }
3030                                 }
3031
3032                                 @Override
3033                                 public void finished(ReadGraphImpl graph) {
3034                                         try {
3035                                                 procedure.finished();
3036                                         } catch (Throwable t2) {
3037                                                 Logger.defaultLogError(t2);
3038                                         }
3039 //                              impl.state.barrier.dec();
3040                                 }
3041
3042                                 @Override
3043                                 public void exception(ReadGraphImpl graph, Throwable t) {
3044                                         try {
3045                                                 procedure.exception(t);
3046                                         } catch (Throwable t2) {
3047                                                 Logger.defaultLogError(t2);
3048                                         }
3049 //                              impl.state.barrier.dec();
3050                                 }
3051
3052                         });
3053                 } catch (DatabaseException e) {
3054                         Logger.defaultLogError(e);
3055                 }
3056         }
3057
3058     final public void forTypes(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3059
3060         assert(subject != null);
3061         assert(procedure != null);
3062
3063         final ListenerBase listener = getListenerBase(procedure);
3064         assert(listener == null);
3065
3066         InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
3067
3068             @Override
3069             public void execute(final ReadGraphImpl graph, IntSet set) {
3070                 procedure.execute(graph, set);
3071             }
3072
3073             @Override
3074             public void exception(ReadGraphImpl graph, Throwable t) {
3075                 procedure.exception(graph, t);
3076             }
3077
3078         };
3079
3080         int sId = querySupport.getId(subject);
3081
3082         try {
3083                         QueryCache.runnerTypes(impl, sId, impl.parent, listener, ip);
3084                 } catch (DatabaseException e) {
3085                         Logger.defaultLogError(e);
3086                 }
3087
3088     }
3089     
3090         @Override
3091         final public IntSet getTypes(final ReadGraphImpl impl, final Resource subject) throws Throwable {
3092
3093                 assert(subject != null);
3094                 
3095                 return QueryCacheBase.resultTypes(impl, querySupport.getId(subject), impl.parent, null);
3096
3097         }
3098
3099         @Override
3100         final public RelationInfo getRelationInfo(final ReadGraphImpl impl, final Resource subject) throws DatabaseException {
3101                 
3102                 assert(subject != null);
3103
3104                 return QueryCache.resultRelationInfoQuery(impl, querySupport.getId(subject), impl.parent, null);
3105
3106         }
3107
3108         @Override
3109         final public void forSupertypes(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3110
3111                 assert(subject != null);
3112                 assert(procedure != null);
3113
3114                 final ListenerBase listener = getListenerBase(procedure);
3115
3116                 try {
3117                         QueryCache.runnerSuperTypes(impl, querySupport.getId(subject), impl.parent, listener, new InternalProcedure<IntSet>() {
3118
3119                                 AtomicBoolean first = new AtomicBoolean(true);
3120
3121                                 @Override
3122                                 public void execute(final ReadGraphImpl graph, IntSet set) {
3123 //                              final HashSet<Resource> result = new HashSet<Resource>();
3124 //                              set.forEach(new TIntProcedure() {
3125 //
3126 //                                      @Override
3127 //                                      public boolean execute(int type) {
3128 //                                              result.add(querySupport.getResource(type));
3129 //                                              return true;
3130 //                                      }
3131 //
3132 //                              });
3133                                         try {
3134                                                 if(first.compareAndSet(true, false)) {
3135                                                         procedure.execute(graph, set);
3136 //                                              impl.state.barrier.dec();
3137                                                 } else {
3138                                                         procedure.execute(impl.newRestart(graph), set);
3139                                                 }
3140                                         } catch (Throwable t2) {
3141                                                 Logger.defaultLogError(t2);
3142                                         }
3143                                 }
3144
3145                                 @Override
3146                                 public void exception(ReadGraphImpl graph, Throwable t) {
3147                                         try {
3148                                                 if(first.compareAndSet(true, false)) {
3149                                                         procedure.exception(graph, t);
3150 //                                              impl.state.barrier.dec();
3151                                                 } else {
3152                                                         procedure.exception(impl.newRestart(graph), t);
3153                                                 }
3154                                         } catch (Throwable t2) {
3155                                                 Logger.defaultLogError(t2);
3156                                         }
3157                                 }
3158
3159                         });
3160                 } catch (DatabaseException e) {
3161                         Logger.defaultLogError(e);
3162                 }
3163
3164         }
3165
3166         @Override
3167         final public void forDirectSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3168
3169                 assert(subject != null);
3170                 assert(procedure != null);
3171
3172                 final ListenerBase listener = getListenerBase(procedure);
3173
3174                 IntProcedure ip = new IntProcedureAdapter() {
3175
3176                         @Override
3177                         public void execute(final ReadGraphImpl graph, int superRelation) {
3178                                 try {
3179                                         procedure.execute(graph, querySupport.getResource(superRelation));
3180                                 } catch (Throwable t2) {
3181                                         Logger.defaultLogError(t2);
3182                                 }
3183                         }
3184
3185                         @Override
3186                         public void finished(final ReadGraphImpl graph) {
3187                                 try {
3188                                         procedure.finished(graph);
3189                                 } catch (Throwable t2) {
3190                                         Logger.defaultLogError(t2);
3191                                 }
3192 //                              impl.state.barrier.dec(this);
3193                         }
3194
3195
3196                         @Override
3197                         public void exception(ReadGraphImpl graph, Throwable t) {
3198                                 try {
3199                                         procedure.exception(graph, t);
3200                                 } catch (Throwable t2) {
3201                                         Logger.defaultLogError(t2);
3202                                 }
3203 //                              impl.state.barrier.dec(this);
3204                         }
3205
3206                 };
3207
3208                 int sId = querySupport.getId(subject); 
3209
3210 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectSuperRelations#" + sId);
3211 //              else impl.state.barrier.inc(null, null);
3212
3213                 try {
3214                         QueryCache.runnerDirectSuperRelations(impl, sId, impl.parent, listener, ip);
3215                 } catch (DatabaseException e) {
3216                         Logger.defaultLogError(e);
3217                 }
3218                 
3219 //              DirectSuperRelations.queryEach(impl, sId, this, impl.parent, listener, ip);
3220
3221         }
3222
3223         @Override
3224         final public void forPossibleSuperrelation(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Resource> procedure) {
3225
3226                 assert(subject != null);
3227                 assert(procedure != null);
3228
3229                 final ListenerBase listener = getListenerBase(procedure);
3230
3231 //              impl.state.barrier.inc();
3232
3233                 PossibleSuperRelation.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
3234
3235         }
3236
3237         @Override
3238         final public void forSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
3239
3240                 assert(subject != null);
3241                 assert(procedure != null);
3242
3243                 final ListenerBase listener = getListenerBase(procedure);
3244
3245                 InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
3246
3247                         @Override
3248                         public void execute(final ReadGraphImpl graph, IntSet set) {
3249 //                              final HashSet<Resource> result = new HashSet<Resource>();
3250 //                              set.forEach(new TIntProcedure() {
3251 //
3252 //                                      @Override
3253 //                                      public boolean execute(int type) {
3254 //                                              result.add(querySupport.getResource(type));
3255 //                                              return true;
3256 //                                      }
3257 //
3258 //                              });
3259                                 try {
3260                                         procedure.execute(graph, set);
3261                                 } catch (Throwable t2) {
3262                                         Logger.defaultLogError(t2);
3263                                 }
3264 //                              impl.state.barrier.dec(this);
3265                         }
3266
3267                         @Override
3268                         public void exception(ReadGraphImpl graph, Throwable t) {
3269                                 try {
3270                                         procedure.exception(graph, t);
3271                                 } catch (Throwable t2) {
3272                                         Logger.defaultLogError(t2);
3273                                 }
3274 //                              impl.state.barrier.dec(this);
3275                         }
3276
3277                 };
3278
3279                 int sId = querySupport.getId(subject);
3280
3281 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#SuperRelations#" + sId);
3282 //              else impl.state.barrier.inc(null, null);
3283
3284                 try {
3285                         QueryCache.runnerSuperRelations(impl, sId, impl.parent, listener, ip);
3286                 } catch (DatabaseException e) {
3287                         Logger.defaultLogError(e);
3288                 }
3289
3290         }
3291
3292         final public byte[] getValue(final ReadGraphImpl impl, final Resource subject) throws DatabaseException {
3293           return getValue(impl, querySupport.getId(subject));
3294         }
3295
3296         final public byte[] getValue(final ReadGraphImpl impl, final int subject) throws DatabaseException {
3297                 return QueryCache.resultValueQuery(impl, subject, impl.parent, null); 
3298         }
3299
3300         @Override
3301         final public void forValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
3302
3303                 assert(subject != null);
3304                 assert(procedure != null);
3305
3306                 int sId = querySupport.getId(subject);
3307
3308 //              if(procedure != null) {
3309                 
3310                         final ListenerBase listener = getListenerBase(procedure);
3311
3312                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3313
3314                                 AtomicBoolean first = new AtomicBoolean(true);
3315
3316                                 @Override
3317                                 public void execute(ReadGraphImpl graph, byte[] result) {
3318                                         try {
3319                                                 if(first.compareAndSet(true, false)) {
3320                                                         procedure.execute(graph, result);
3321 //                                                      impl.state.barrier.dec(this);
3322                                                 } else {
3323                                                         procedure.execute(impl.newRestart(graph), result);
3324                                                 }
3325                                         } catch (Throwable t2) {
3326                                                 Logger.defaultLogError(t2);
3327                                         }
3328                                 }
3329
3330                                 @Override
3331                                 public void exception(ReadGraphImpl graph, Throwable t) {
3332                                         try {
3333                                                 if(first.compareAndSet(true, false)) {
3334                                                         procedure.exception(graph, t);
3335 //                                                      impl.state.barrier.dec(this);
3336                                                 } else {
3337                                                         procedure.exception(impl.newRestart(graph), t);
3338                                                 }
3339                                         } catch (Throwable t2) {
3340                                                 Logger.defaultLogError(t2);
3341                                         }
3342                                 }
3343
3344                         };
3345
3346 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
3347 //                      else impl.state.barrier.inc(null, null);
3348
3349                         try {
3350                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3351                         } catch (DatabaseException e) {
3352                                 throw new IllegalStateException("Internal error");
3353                         }
3354
3355 //              } else {
3356 //
3357 //                      return QueryCacheBase.runnerValueQuery(impl, sId, impl.parent, null, null);
3358 //                      
3359 //              }
3360 //              
3361 //              throw new IllegalStateException("Internal error");
3362
3363         }
3364
3365         @Override
3366         final public void forPossibleValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
3367
3368                 assert(subject != null);
3369                 assert(procedure != null);
3370
3371                 final ListenerBase listener = getListenerBase(procedure);
3372
3373                 if(impl.parent != null || listener != null) {
3374
3375                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3376
3377                                 AtomicBoolean first = new AtomicBoolean(true);
3378
3379                                 @Override
3380                                 public void execute(ReadGraphImpl graph, byte[] result) {
3381                                         try {
3382                                                 if(first.compareAndSet(true, false)) {
3383                                                         procedure.execute(graph, result);
3384 //                                                      impl.state.barrier.dec(this);
3385                                                 } else {
3386                                                         procedure.execute(impl.newRestart(graph), result);
3387                                                 }
3388                                         } catch (Throwable t2) {
3389                                                 Logger.defaultLogError(t2);
3390                                         }
3391                                 }
3392
3393                                 @Override
3394                                 public void exception(ReadGraphImpl graph, Throwable t) {
3395                                         try {
3396                                                 if(first.compareAndSet(true, false)) {
3397                                                         procedure.exception(graph, t);
3398 //                                                      impl.state.barrier.dec(this);
3399                                                 } else {
3400                                                         procedure.exception(impl.newRestart(graph), t);
3401                                                 }
3402                                         } catch (Throwable t2) {
3403                                                 Logger.defaultLogError(t2);
3404                                         }
3405                                 }
3406
3407                         };
3408
3409                         int sId = querySupport.getId(subject);
3410
3411 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
3412 //                      else impl.state.barrier.inc(null, null);
3413
3414                         try {
3415                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3416                         } catch (DatabaseException e) {
3417                                 Logger.defaultLogError(e);
3418                         }
3419
3420                 } else {
3421
3422                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
3423
3424                                 @Override
3425                                 public void execute(ReadGraphImpl graph, byte[] result) {
3426
3427                                         procedure.execute(graph, result);
3428
3429                                 }
3430
3431                                 @Override
3432                                 public void exception(ReadGraphImpl graph, Throwable t) {
3433
3434                                         procedure.exception(graph, t);
3435
3436                                 }
3437
3438                         };
3439
3440                         int sId = querySupport.getId(subject);
3441
3442                         try {
3443                                 QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip);
3444                         } catch (DatabaseException e) {
3445                                 Logger.defaultLogError(e);
3446                         }
3447
3448                 }
3449
3450         }
3451
3452         @Override
3453         final public void forInverse(final ReadGraphImpl impl, final Resource relation, final AsyncProcedure<Resource> procedure) {
3454
3455                 assert(relation != null);
3456                 assert(procedure != null);
3457
3458                 final ListenerBase listener = getListenerBase(procedure);
3459
3460                 IntProcedure ip = new IntProcedure() {
3461
3462                         private int result = 0;
3463                         
3464                     final AtomicBoolean found = new AtomicBoolean(false);
3465                     final AtomicBoolean done = new AtomicBoolean(false);
3466
3467                         @Override
3468                         public void finished(ReadGraphImpl graph) {
3469                                 
3470                         // Shall fire exactly once!
3471                         if(done.compareAndSet(false, true)) {
3472                                 try {
3473                                         if(result == 0) {
3474                                                         procedure.exception(graph, new NoInverseException(""));
3475 //                                              impl.state.barrier.dec(this);
3476                                         } else {
3477                                                 procedure.execute(graph, querySupport.getResource(result));
3478 //                                              impl.state.barrier.dec(this);
3479                                         }
3480                                 } catch (Throwable t) {
3481                                         Logger.defaultLogError(t);
3482                                 }
3483                         }
3484                         
3485                         }
3486
3487                         @Override
3488                         public void execute(ReadGraphImpl graph, int i) {
3489                                 
3490                                 if(found.compareAndSet(false, true)) {
3491                                         this.result = i;
3492                                 } else {
3493                                         // Shall fire exactly once!
3494                                         if(done.compareAndSet(false, true)) {
3495                                                 try {
3496                                                         procedure.exception(graph, new ManyObjectsForFunctionalRelationException("Multiple items e.g. " + this.result + " and " + result));
3497 //                                                      impl.state.barrier.dec(this);
3498                                                 } catch (Throwable t) {
3499                                                 Logger.defaultLogError(t);
3500                                                 }
3501                                         }
3502                                 }
3503                                 
3504                         }
3505
3506                         @Override
3507                         public void exception(ReadGraphImpl graph, Throwable t) {
3508                                 // Shall fire exactly once!
3509                                 if(done.compareAndSet(false, true)) {
3510                                         try {
3511                                                 procedure.exception(graph, t);
3512 //                                              impl.state.barrier.dec(this);
3513                                         } catch (Throwable t2) {
3514                                         Logger.defaultLogError(t2);
3515                                         }
3516                                 }
3517                         }
3518
3519                 };
3520
3521                 int sId = querySupport.getId(relation);
3522
3523 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectObjects#" + sId);
3524 //              else impl.state.barrier.inc(null, null);
3525
3526                 try {
3527                         QueryCache.runnerObjects(impl, sId, getInverseOf(), impl.parent, listener, ip);
3528                 } catch (DatabaseException e) {
3529                         Logger.defaultLogError(e);
3530                 }
3531
3532         }
3533
3534         @Override
3535         final public void forResource(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
3536
3537                 assert(id != null);
3538                 assert(procedure != null);
3539
3540                 InternalProcedure<Integer> ip = new InternalProcedure<Integer>() {
3541
3542                         @Override
3543                         public void execute(ReadGraphImpl graph, Integer result) {
3544                                 try {
3545                                         procedure.execute(graph, querySupport.getResource(result));
3546                                 } catch (Throwable t2) {
3547                                         Logger.defaultLogError(t2);
3548                                 }
3549 //                              impl.state.barrier.dec(this);
3550                         }   
3551
3552                         @Override
3553                         public void exception(ReadGraphImpl graph, Throwable t) {
3554
3555                                 try {
3556                                         procedure.exception(graph, t);
3557                                 } catch (Throwable t2) {
3558                                         Logger.defaultLogError(t2);
3559                                 }
3560 //                              impl.state.barrier.dec(this);
3561                         }
3562
3563                 };
3564
3565 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "Resource");
3566 //              else impl.state.barrier.inc(null, null);
3567
3568                 forResource(impl, id, impl.parent, ip);
3569
3570         }
3571
3572         @Override
3573         final public void forBuiltin(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
3574
3575                 assert(id != null);
3576                 assert(procedure != null);
3577
3578 //              impl.state.barrier.inc();
3579
3580                 try {
3581                         forBuiltin(impl, id, impl.parent, new InternalProcedure<Integer>() {
3582
3583                                 @Override
3584                                 public void execute(ReadGraphImpl graph, Integer result) {
3585                                         try {
3586                                                 procedure.execute(graph, querySupport.getResource(result)); 
3587                                         } catch (Throwable t2) {
3588                                                 Logger.defaultLogError(t2);
3589                                         }
3590 //                              impl.state.barrier.dec();
3591                                 }   
3592
3593                                 @Override
3594                                 public void exception(ReadGraphImpl graph, Throwable t) {
3595                                         try {
3596                                                 procedure.exception(graph, t);
3597                                         } catch (Throwable t2) {
3598                                                 Logger.defaultLogError(t2);
3599                                         }
3600 //                              impl.state.barrier.dec();
3601                                 }
3602
3603                         });
3604                 } catch (DatabaseException e) {
3605                         Logger.defaultLogError(e);
3606                 }
3607
3608         }
3609
3610         @Override
3611         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
3612
3613                 assert(subject != null);
3614                 assert(procedure != null);
3615
3616                 final ListenerBase listener = getListenerBase(procedure);
3617
3618                 try {
3619                         IntSet result = QueryCache.resultDirectPredicates(impl, querySupport.getId(subject), impl.parent, listener);
3620                         procedure.execute(impl, !result.isEmpty());
3621                 } catch (DatabaseException e) {
3622                         procedure.exception(impl, e);
3623                 }
3624                         
3625         }
3626
3627         @Override
3628         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Boolean> procedure) {
3629
3630                 assert(subject != null);
3631                 assert(predicate != null);
3632                 assert(procedure != null);
3633
3634                 AsyncMultiProcedure<Resource> ip = new AsyncMultiProcedureAdapter<Resource>() {
3635
3636                         boolean found = false;
3637
3638                         @Override
3639                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
3640                                 found = true;
3641                         }
3642
3643                         @Override
3644                         synchronized public void finished(AsyncReadGraph graph) {
3645                                 try {
3646                                         procedure.execute(graph, found);
3647                                 } catch (Throwable t2) {
3648                                         Logger.defaultLogError(t2);
3649                                 }
3650 //                              impl.state.barrier.dec(this);
3651                         }
3652
3653                         @Override
3654                         public void exception(AsyncReadGraph graph, Throwable t) {
3655                                 try {
3656                                         procedure.exception(graph, t);
3657                                 } catch (Throwable t2) {
3658                                         Logger.defaultLogError(t2);
3659                                 }
3660 //                              impl.state.barrier.dec(this);
3661                         }
3662
3663                 };
3664
3665 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#ForEachObject#" + subject + "#" + predicate);
3666 //              else impl.state.barrier.inc(null, null);
3667
3668                 forEachObject(impl, subject, predicate, ip);
3669
3670         }
3671
3672         @Override
3673         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final Resource object, final AsyncProcedure<Boolean> procedure) {
3674
3675                 assert(subject != null);
3676                 assert(predicate != null);
3677                 assert(procedure != null);
3678
3679 //              impl.state.barrier.inc();
3680
3681                 forEachObject(impl, subject, predicate, new AsyncMultiProcedureAdapter<Resource>() {
3682
3683                         boolean found = false;
3684
3685                         @Override
3686                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
3687                                 if(resource.equals(object)) found = true;
3688                         }
3689
3690                         @Override
3691                         synchronized public void finished(AsyncReadGraph graph) {
3692                                 try {
3693                                         procedure.execute(graph, found);
3694                                 } catch (Throwable t2) {
3695                                         Logger.defaultLogError(t2);
3696                                 }
3697 //                              impl.state.barrier.dec();
3698                         }
3699
3700                         @Override
3701                         public void exception(AsyncReadGraph graph, Throwable t) {
3702                                 try {
3703                                         procedure.exception(graph, t);
3704                                 } catch (Throwable t2) {
3705                                         Logger.defaultLogError(t2);
3706                                 }
3707 //                              impl.state.barrier.dec();
3708                         }
3709
3710                 });
3711
3712         }
3713
3714         @Override
3715         final public void forHasValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
3716
3717                 assert(subject != null);
3718                 assert(procedure != null);
3719
3720                 final ListenerBase listener = getListenerBase(procedure);
3721
3722 //              impl.state.barrier.inc();
3723
3724                 try {
3725                         QueryCache.runnerValueQuery(impl, querySupport.getId(subject), impl.parent, listener, new InternalProcedure<byte[]>() {
3726
3727                                 @Override
3728                                 public void execute(ReadGraphImpl graph, byte[] object) {
3729                                         boolean result = object != null;
3730                                         try {
3731                                                 procedure.execute(graph, result);
3732                                         } catch (Throwable t2) {
3733                                                 Logger.defaultLogError(t2);
3734                                         }
3735 //                              impl.state.barrier.dec();
3736                                 }
3737
3738                                 @Override
3739                                 public void exception(ReadGraphImpl graph, Throwable t) {
3740                                         try {
3741                                                 procedure.exception(graph, t);
3742                                         } catch (Throwable t2) {
3743                                                 Logger.defaultLogError(t2);
3744                                         }
3745 //                              impl.state.barrier.dec();
3746                                 }
3747
3748                         });
3749                 } catch (DatabaseException e) {
3750                         Logger.defaultLogError(e);
3751                 }
3752
3753         }
3754
3755         @Override
3756         final public void forOrderedSet(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3757
3758                 assert(subject != null);
3759                 assert(procedure != null);
3760
3761                 final ListenerBase listener = getListenerBase(procedure);
3762
3763                 try {
3764                         
3765                         QueryCache.runnerOrderedSet(impl, querySupport.getId(subject), impl.parent, listener, new IntProcedure() {
3766
3767                                 @Override
3768                                 public void exception(ReadGraphImpl graph, Throwable t) {
3769                                         try {
3770                                                 procedure.exception(graph, t);
3771                                         } catch (Throwable t2) {
3772                                                 Logger.defaultLogError(t2);
3773                                         }
3774 //                              impl.state.barrier.dec();
3775                                 }
3776
3777                                 @Override
3778                                 public void execute(ReadGraphImpl graph, int i) {
3779                                         try {
3780                                                 procedure.execute(graph, querySupport.getResource(i));
3781                                         } catch (Throwable t2) {
3782                                                 Logger.defaultLogError(t2);
3783                                         }
3784                                 }
3785
3786                                 @Override
3787                                 public void finished(ReadGraphImpl graph) {
3788                                         try {
3789                                                 procedure.finished(graph);
3790                                         } catch (Throwable t2) {
3791                                                 Logger.defaultLogError(t2);
3792                                         }
3793 //                              impl.state.barrier.dec();
3794                                 }
3795
3796                         });
3797                 } catch (DatabaseException e) {
3798                         Logger.defaultLogError(e);
3799                 }
3800
3801         }
3802
3803 //      @Override
3804 //      final public <T> void query(final ReadGraphImpl impl, final AsyncRead<T> request, final CacheEntry parent, final AsyncProcedure<T> procedure, ListenerBase listener) throws DatabaseException {
3805 //
3806 //              assert(request != null);
3807 //              assert(procedure != null);
3808 //
3809 //              QueryCache.runnerAsyncReadEntry(impl, request, parent, listener, procedure);
3810 //
3811 //      }
3812
3813 //      @Override
3814 //      final public <T> T tryQuery(final ReadGraphImpl graph, final Read<T> request) throws DatabaseException {
3815 //
3816 //              assert(graph != null);
3817 //              assert(request != null);
3818 //
3819 //              final ReadEntry entry = (ReadEntry)cache.getCached(request);
3820 //              if(entry != null && entry.isReady()) {
3821 //                  return (T)entry.get(graph, this, null);
3822 //              } else {
3823 //                      return request.perform(graph);
3824 //              }
3825 //
3826 //      }
3827
3828 //    final public <T> T tryQuery(final ReadGraphImpl graph, final ExternalRead<T> request) throws DatabaseException {
3829 //
3830 //        assert(graph != null);
3831 //        assert(request != null);
3832 //
3833 //        final ExternalReadEntry<T> entry = cache.externalReadMap.get(request);
3834 //        if(entry != null && entry.isReady()) {
3835 //            if(entry.isExcepted()) {
3836 //                Throwable t = (Throwable)entry.getResult();
3837 //                if(t instanceof DatabaseException) throw (DatabaseException)t;
3838 //                else throw new DatabaseException(t);
3839 //            } else {
3840 //                return (T)entry.getResult();
3841 //            }            
3842 //        } else {
3843 //
3844 //            final DataContainer<T> result = new DataContainer<T>();
3845 //            final DataContainer<Throwable> exception = new DataContainer<Throwable>();
3846 //            
3847 //            request.register(graph, new Listener<T>() {
3848 //                
3849 //                @Override
3850 //                public void exception(Throwable t) {
3851 //                    exception.set(t);
3852 //                }
3853 //
3854 //                @Override
3855 //                public void execute(T t) {
3856 //                    result.set(t);
3857 //                }
3858 //
3859 //                @Override
3860 //                public boolean isDisposed() {
3861 //                    return true;
3862 //                }
3863 //            
3864 //            });
3865 //            
3866 //            Throwable t = exception.get();
3867 //            if(t != null) {
3868 //                if(t instanceof DatabaseException) throw (DatabaseException)t;
3869 //                else throw new DatabaseException(t);
3870 //            }
3871 //            
3872 //            return result.get();
3873 //
3874 //        }
3875 //
3876 //    }
3877         
3878 //      @Override
3879 //      final public <T> void tryQuery(final ReadGraphImpl graph, final AsyncRead<T> request, AsyncProcedure<T> procedure) {
3880 //
3881 //              assert(graph != null);
3882 //              assert(request != null);
3883 //
3884 //              final AsyncReadEntry entry = cache.asyncReadMap.get(request);
3885 //              if(entry != null && entry.isReady()) {
3886 //                      if(entry.isExcepted()) {
3887 //                              procedure.exception(graph, (Throwable)entry.getResult());
3888 //                      } else {
3889 //                              procedure.execute(graph, (T)entry.getResult());
3890 //                      }
3891 //              } else {
3892 //                      request.perform(graph, procedure);
3893 //              }
3894 //
3895 //      }
3896
3897         @Override
3898         final public <T> void query(final ReadGraphImpl impl, final MultiRead<T> request, final CacheEntry parent, final SyncMultiProcedure<T> procedure, ListenerBase listener) {
3899
3900                 assert(request != null);
3901                 assert(procedure != null);
3902
3903                 try {
3904
3905                         queryMultiRead(impl, request, parent, listener, procedure);
3906                         
3907                 } catch (DatabaseException e) {
3908                         
3909                         throw new IllegalStateException(e);
3910                         
3911                 }
3912
3913         }
3914
3915         @Override
3916         final public <T> void query(final ReadGraphImpl impl, final AsyncMultiRead<T> request, final CacheEntry parent, final AsyncMultiProcedure<T> procedure, ListenerBase listener) {
3917
3918                 assert(request != null);
3919                 assert(procedure != null);
3920
3921 //              impl.state.barrier.inc();
3922
3923                 runAsyncMultiRead(impl, request, parent, listener, new AsyncMultiProcedure<T>() {
3924
3925                         public void execute(AsyncReadGraph graph, T result) {
3926
3927                                 try {
3928                                         procedure.execute(graph, result);
3929                                 } catch (Throwable t2) {
3930                                         Logger.defaultLogError(t2);
3931                                 }
3932                         }
3933
3934                         @Override
3935                         public void finished(AsyncReadGraph graph) {
3936
3937                                 try {
3938                                         procedure.finished(graph);
3939                                 } catch (Throwable t2) {
3940                                         Logger.defaultLogError(t2);
3941                                 }
3942
3943 //                              impl.state.barrier.dec();
3944
3945                         }
3946
3947                         @Override
3948                         public String toString() {
3949                                 return procedure.toString();
3950                         }
3951
3952                         @Override
3953                         public void exception(AsyncReadGraph graph, Throwable t) {
3954
3955                                 try {
3956                                         procedure.exception(graph, t);
3957                                 } catch (Throwable t2) {
3958                                         Logger.defaultLogError(t2);
3959                                 }
3960
3961 //                              impl.state.barrier.dec();
3962
3963                         }
3964
3965                 });
3966
3967         }
3968
3969 //      @Override
3970 //      final public <T> void query(final ReadGraphImpl impl, final ExternalRead<T> request, final CacheEntry parent, final Procedure<T> procedure, ListenerBase listener) throws DatabaseException {
3971 //
3972 //              assert(request != null);
3973 //              assert(procedure != null);
3974 //
3975 //              try {
3976 //              
3977 //                      queryPrimitiveRead(impl, request, parent, listener, new AsyncProcedure<T>() {
3978 //      
3979 //                              @Override
3980 //                              public String toString() {
3981 //                                      return procedure.toString();
3982 //                              }
3983 //      
3984 //                              @Override
3985 //                              public void execute(AsyncReadGraph graph, T result) {
3986 //                                      try {
3987 //                                              procedure.execute(result);
3988 //                                      } catch (Throwable t2) {
3989 //                                              Logger.defaultLogError(t2);
3990 //                                      }
3991 //                              }
3992 //
3993 //                              @Override
3994 //                              public void exception(AsyncReadGraph graph, Throwable throwable) {
3995 //                                      try {
3996 //                                              procedure.exception(throwable);
3997 //                                      } catch (Throwable t2) {
3998 //                                              Logger.defaultLogError(t2);
3999 //                                      }
4000 //                              }
4001 //      
4002 //                      });
4003 //                      
4004 //              } catch (DatabaseException e) {
4005 //                      
4006 //                      throw new IllegalStateException(e);
4007 //                      
4008 //              }
4009 //
4010 //      }
4011
4012         @Override
4013         public VirtualGraph getProvider(Resource subject, Resource predicate, Resource object) {
4014                 
4015                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
4016                 
4017         }
4018         
4019         @Override
4020         public VirtualGraph getProvider(Resource subject, Resource predicate) {
4021                 
4022                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate));
4023                 
4024         }
4025
4026         @Override
4027         public VirtualGraph getValueProvider(Resource subject) {
4028                 
4029                 return querySupport.getValueProvider(querySupport.getId(subject));
4030                 
4031         }
4032
4033         public boolean resumeTasks(ReadGraphImpl graph) {
4034
4035                 return querySupport.resume(graph);
4036
4037         }
4038         
4039         public boolean isImmutable(int resourceId) {
4040                 return querySupport.isImmutable(resourceId);
4041         }
4042
4043         public boolean isImmutable(Resource resource) {
4044                 ResourceImpl impl = (ResourceImpl)resource;
4045                 return isImmutable(impl.id);
4046         }
4047         
4048         private Layer0 L0;
4049         
4050         public Layer0 getL0(ReadGraph graph) {
4051                 if(L0 == null) {
4052                         L0 = Layer0.getInstance(graph);
4053                 }
4054                 return L0;
4055         }
4056
4057     public static ThreadLocal<Integer> thread = new ThreadLocal<Integer>() {
4058         protected Integer initialValue() {
4059             return -1;
4060         }
4061     };
4062         
4063 }