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