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