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