]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java
Fixed all line endings of the repository
[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                 }
2012
2013                 b.close();
2014                 
2015                 Development.histogram.clear();
2016
2017                 return "OK";
2018
2019         }
2020         
2021         public synchronized String reportQueries(File file) throws IOException {
2022
2023                 System.err.println("reportQueries " + file.getAbsolutePath());
2024
2025                 if (!isAlive())
2026                         return "Disposed!";
2027
2028                 PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
2029
2030                 long start = System.nanoTime();
2031
2032 //              ArrayList<CacheEntry> all = ;
2033                 
2034                 Map<CacheEntry, Set<CacheEntry>> workarea = new HashMap<CacheEntry, Set<CacheEntry>>();
2035                 Collection<CacheEntryBase> caches = allCaches(new CacheCollectionResult()).toCollection();
2036                 for(CacheEntryBase entry : caches) {
2037                         processParentReport(entry, workarea);
2038                 }
2039                 
2040                 //        for(CacheEntry e : all) System.err.println("entry: " + e);
2041
2042                 long duration = System.nanoTime() - start;
2043                 System.err.println("Query root set in " + 1e-9*duration + "s.");
2044
2045                 start = System.nanoTime();
2046
2047                 HashMap<CacheEntry, Integer> flagMap = new HashMap<CacheEntry, Integer>(); 
2048
2049                 int listeners = 0;
2050
2051                 for(CacheEntry entry : workarea.keySet()) {
2052                         boolean listener = hasListenerAfterDisposing(entry);
2053                         boolean hasParents = entry.getParents(this).iterator().hasNext();
2054                         if(listener) {
2055                                 // Bound
2056                                 flagMap.put(entry, 0);
2057                         } else if (!hasParents) {
2058                                 // Unbound
2059                                 flagMap.put(entry, 1);
2060                         } else {
2061                                 // Unknown
2062                                 flagMap.put(entry, 2);
2063                         }
2064                         //              // Write leaf bit
2065                         //              entry.flags |= 4;
2066                 }
2067
2068                 boolean done = true;
2069                 int loops = 0;
2070
2071                 do {
2072
2073                         done = true;
2074
2075                         long start2 = System.nanoTime();
2076
2077                         int boundCounter = 0;
2078                         int unboundCounter = 0;
2079                         int unknownCounter = 0;
2080
2081                         for(CacheEntry entry : workarea.keySet()) {
2082
2083                                 //System.err.println("process " + entry);
2084
2085                                 int flags = flagMap.get(entry);
2086                                 int bindStatus = flags & 3;
2087
2088                                 if(bindStatus == 0) boundCounter++;
2089                                 else if(bindStatus == 1) unboundCounter++;
2090                                 else if(bindStatus == 2) unknownCounter++;
2091
2092                                 if(bindStatus < 2) continue;
2093
2094                                 int newStatus = 1;
2095                                 for(CacheEntry parent : entry.getParents(this)) {
2096
2097                                         if(parent.isDiscarded()) flagMap.put(parent, 1);
2098
2099                                         int flags2 = flagMap.get(parent);
2100                                         int bindStatus2 = flags2 & 3;
2101                                         // Parent is bound => child is bound
2102                                         if(bindStatus2 == 0) {
2103                                                 newStatus = 0;
2104                                                 break;
2105                                         }
2106                                         // Parent is unknown => child is unknown
2107                                         else if (bindStatus2 == 2) {
2108                                                 newStatus = 2;
2109                                                 done = false;
2110                                                 break;
2111                                         }
2112                                 }
2113
2114                                 flagMap.put(entry, newStatus);
2115
2116                         }
2117
2118                         duration = System.nanoTime() - start2;
2119                         System.err.println("Query analysis pass (" + boundCounter + "/" + unboundCounter + "/" + unknownCounter + ") in "+ 1e-9*duration + "s.");
2120                         b.println("Query analysis pass (" + boundCounter + "/" + unboundCounter + "/" + unknownCounter + ") in "+ 1e-9*duration + "s.");
2121
2122                 } while(!done && loops++ < 20);
2123
2124                 if(loops >= 20) {
2125
2126                         for(CacheEntry entry : workarea.keySet()) {
2127
2128                                 int bindStatus = flagMap.get(entry);
2129                                 if(bindStatus == 2) System.err.println("Undefined bind status for " + entry);
2130
2131                         }
2132
2133                 }
2134
2135                 duration = System.nanoTime() - start;
2136                 System.err.println("Query analysis in " + 1e-9*duration + "s.");
2137
2138                 Map<Class<?>, Integer> counts = new HashMap<Class<?>, Integer>();
2139
2140                 for(CacheEntry entry : workarea.keySet()) {
2141                         Class<?> clazz = entry.getClass();
2142                         if(entry instanceof ReadEntry) clazz = ((ReadEntry)entry).request.getClass(); 
2143                         else if(entry instanceof MultiReadEntry) clazz = ((MultiReadEntry)entry).request.getClass(); 
2144                         else if(entry instanceof AsyncReadEntry) clazz = ((AsyncReadEntry)entry).request.getClass(); 
2145                         else if(entry instanceof AsyncMultiReadEntry) clazz = ((AsyncMultiReadEntry)entry).request.getClass(); 
2146                         else if(entry instanceof ExternalReadEntry) clazz = ((ExternalReadEntry)entry).request.getClass(); 
2147                         Integer c = counts.get(clazz);
2148                         if(c == null) counts.put(clazz, -1);
2149                         else counts.put(clazz, c-1);
2150                 }
2151
2152                 b.print("// Simantics DB client query report file\n");
2153                 b.print("// This file contains the following information\n");
2154                 b.print("// -The amount of cached query instances per query class\n");
2155                 b.print("// -The sizes of retained child sets\n");
2156                 b.print("// -List of parents for each query (search for 'P <query name>')\n");
2157                 b.print("//  -Followed by status, where\n");
2158                 b.print("//   -0=bound\n");
2159                 b.print("//   -1=free\n");
2160                 b.print("//   -2=unknown\n");
2161                 b.print("//   -L=has listener\n");
2162                 b.print("// -List of children for each query (search for 'C <query name>')\n");
2163
2164                 b.print("----------------------------------------\n");
2165
2166                 b.print("// Queries by class\n");
2167                 for(Pair<Class<?>, Integer> p : CollectionUtils.valueSortedEntries(counts)) {
2168                         b.print(-p.second + " " + p.first.getName() + "\n");
2169                 }
2170
2171                 Map<CacheEntry, Integer> hist = new HashMap<CacheEntry, Integer>();
2172                 for(CacheEntry e : workarea.keySet())
2173                         hist.put(e, -1);
2174                 
2175                 boolean changed = true;
2176                 int iter = 0;
2177                 while(changed && iter++<50) {
2178                         
2179                         changed = false;
2180                         
2181                         Map<CacheEntry, Integer> newHist = new HashMap<CacheEntry, Integer>();
2182                         for(CacheEntry e : workarea.keySet())
2183                                 newHist.put(e, -1);
2184
2185                         for(Map.Entry<CacheEntry, Set<CacheEntry>> e : workarea.entrySet()) {
2186                                 Integer c = hist.get(e.getKey());
2187                                 for(CacheEntry p : e.getValue()) {
2188                                         Integer i = newHist.get(p);
2189                                         newHist.put(p, i+c);
2190                                 }
2191                         }
2192                         for(CacheEntry e : workarea.keySet()) {
2193                                 Integer value = newHist.get(e);
2194                                 Integer old = hist.get(e);
2195                                 if(!value.equals(old)) {
2196                                         hist.put(e, value);
2197 //                                      System.err.println("hist " + e + ": " + old + " => " + value);
2198                                         changed = true;
2199                                 }
2200                         }
2201                         
2202                         System.err.println("Retained set iteration " + iter);
2203
2204                 }
2205
2206                 b.print("// Queries by retained set\n");
2207                 for(Pair<CacheEntry, Integer> p : CollectionUtils.valueSortedEntries(hist)) {
2208                         b.print("" + -p.second + " " + p.first + "\n");
2209                 }
2210
2211                 HashMap<CacheEntry, Collection<CacheEntry>> inverse = new HashMap<CacheEntry, Collection<CacheEntry>>();
2212
2213                 b.print("// Entry parent listing\n");
2214                 for(CacheEntry entry : workarea.keySet()) {
2215                         int status = flagMap.get(entry);
2216                         boolean hasListener = hasListenerAfterDisposing(entry);
2217                         b.print("Q " + entry.toString());
2218                         if(hasListener) {
2219                                 b.print(" (L" + status + ")");
2220                                 listeners++;
2221                         } else {
2222                                 b.print(" (" + status + ")");
2223                         }
2224                         b.print("\n");
2225                         for(CacheEntry parent : workarea.get(entry)) {
2226                                 Collection<CacheEntry> inv = inverse.get(parent);
2227                                 if(inv == null) {
2228                                         inv = new ArrayList<CacheEntry>();
2229                                         inverse.put(parent, inv);
2230                                 }
2231                                 inv.add(entry);
2232                                 b.print("  " + parent.toString());
2233                                 b.print("\n");
2234                         }
2235                 }
2236
2237                 b.print("// Entry child listing\n");
2238                 for(Map.Entry<CacheEntry, Collection<CacheEntry>> entry : inverse.entrySet()) {
2239                         b.print("C " + entry.getKey().toString());
2240                         b.print("\n");
2241                         for(CacheEntry child : entry.getValue()) {
2242                                 Integer h = hist.get(child);
2243                                 if(h != null) {
2244                                         b.print("  " + h);
2245                                 } else {
2246                                         b.print("  <no children>");
2247                                 }
2248                                 b.print("  " + child.toString());
2249                                 b.print("\n");
2250                         }
2251                 }
2252
2253                 b.print("#queries: " + workarea.keySet().size() + "\n");
2254                 b.print("#listeners: " + listeners + "\n");
2255
2256                 b.close();
2257
2258                 return "Dumped " + workarea.keySet().size() + " queries.";
2259
2260         }
2261
2262         class UpdateEntry {
2263
2264                 public CacheEntry caller;
2265
2266                 public CacheEntry entry;
2267
2268                 public int         indent;
2269
2270                 public UpdateEntry(CacheEntry caller, CacheEntry entry, int indent) {
2271                         this.caller = caller;
2272                         this.entry = entry;
2273                         this.indent = indent;
2274                 }
2275
2276         };
2277
2278         boolean removeQuery(CacheEntry entry) {
2279
2280                 // This entry has been removed before. No need to do anything here.
2281                 if(entry.isDiscarded()) return false;
2282
2283                 assert (!entry.isDiscarded());
2284
2285                 Query query = entry.getQuery();
2286
2287                 query.removeEntry(this);
2288
2289                 updates++;
2290                 size--;
2291
2292                 if((entry.getGCStatus() & CacheEntry.HAS_BEEN_BOUND) != 0)
2293                         boundQueries--;
2294                 
2295                 entry.discard();
2296
2297                 return true;
2298
2299         }
2300
2301         /**
2302          * 
2303          * @return true if this entry is being listened
2304          */
2305         private boolean updateQuery(UpdateEntry e, LinkedList<UpdateEntry> todo, IdentityHashMap<CacheEntry, CacheEntry> immediates) throws DatabaseException {
2306
2307                 assert (e != null);
2308
2309                 CacheEntry entry = e.entry;
2310
2311 //              System.err.println("updateQuery " + entry);
2312                 
2313                 /*
2314                  * If the dependency graph forms a DAG, some entries are inserted in the
2315                  * todo list many times. They only need to be processed once though.
2316                  */
2317                 if (entry.isDiscarded()) {
2318                         if (Development.DEVELOPMENT) {
2319                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2320                                         System.out.print("D");
2321                                         for (int i = 0; i < e.indent; i++)
2322                                                 System.out.print(" ");
2323                                         System.out.println(entry.getQuery());
2324                                 }
2325                         }
2326 //                      System.err.println(" => DISCARDED");
2327                         return false;
2328                 }
2329
2330                 if (entry.isRefuted()) {
2331                         if (Development.DEVELOPMENT) {
2332                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2333                                         System.out.print("R");
2334                                         for (int i = 0; i < e.indent; i++)
2335                                                 System.out.print(" ");
2336                                         System.out.println(entry.getQuery());
2337                                 }
2338                         }
2339                         return false;
2340                 }
2341
2342                 if (entry.isExcepted()) {
2343                         if (Development.DEVELOPMENT) {
2344                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2345                                         System.out.print("E");
2346                                 }
2347                         }
2348                 }
2349
2350                 if (entry.isPending()) {
2351                         if (Development.DEVELOPMENT) {
2352                                 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2353                                         System.out.print("P");
2354                                 }
2355                         }
2356                 }
2357
2358                 updates++;
2359
2360                 if (Development.DEVELOPMENT) {
2361                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2362                                 System.out.print("U ");
2363                                 for (int i = 0; i < e.indent; i++)
2364                                         System.out.print(" ");
2365                                 System.out.print(entry.getQuery());
2366                         }
2367                 }
2368
2369                 Query query = entry.getQuery();
2370                 int type = query.type();
2371
2372                 boolean hasListener = hasListener(entry); 
2373
2374                 if (Development.DEVELOPMENT) {
2375                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2376                                 if(hasListener(entry)) {
2377                                         System.out.println(" (L)");
2378                                 } else {
2379                                         System.out.println("");
2380                                 }
2381                         }
2382                 }
2383
2384                 if(entry.isPending() || entry.isExcepted()) {
2385
2386                         // If updated
2387                         if ((type & RequestFlags.UPDATE_MASK) == RequestFlags.IMMEDIATE_UPDATE) {
2388
2389                                 immediates.put(entry, entry);
2390
2391                         } else {
2392
2393                                 if(hasListener) {
2394                                         entry.refute();
2395                                 } else {
2396                                         removeQuery(entry);
2397                                 }
2398
2399                         }
2400
2401                 } else {
2402
2403                         // If updated
2404                         if ((type & RequestFlags.UPDATE_MASK) == RequestFlags.IMMEDIATE_UPDATE) {
2405
2406                                 immediates.put(entry, entry);
2407
2408                         } else {
2409
2410                                 if(hasListener) {
2411                                         entry.refute();
2412                                 } else {
2413                                         removeQuery(entry);
2414                                 }
2415
2416                         }
2417
2418                 }
2419
2420 //              System.err.println(" => FOO " + type);
2421
2422                 if (hasListener) {
2423                         ArrayList<ListenerEntry> entries = listeners.get(entry);
2424                         if(entries != null) {
2425                                 for (ListenerEntry le : entries) {
2426                                         scheduleListener(le);
2427                                 }
2428                         }
2429                 }
2430
2431                 // If invalid, update parents
2432                 if (type == RequestFlags.INVALIDATE) {
2433                         updateParents(e.indent, entry, todo);
2434                 }
2435
2436                 return hasListener;
2437
2438         }
2439
2440         private void updateParents(int indent, CacheEntry entry, LinkedList<UpdateEntry> todo) {
2441
2442                 Iterable<CacheEntry> oldParents = entry.getParents(this);
2443                 for (CacheEntry parent : oldParents) {
2444 //                      System.err.println("updateParents " + entry + " => " + parent);
2445                         if(!parent.isDiscarded())
2446                                 todo.push(new UpdateEntry(entry, parent, indent + 2));
2447                 }
2448
2449         }
2450
2451         private boolean pruneListener(ListenerEntry entry) {
2452                 if (entry.base.isDisposed()) {
2453                         removeListener(entry);
2454                         return true;
2455                 } else {
2456                         return false;
2457                 }
2458         }
2459
2460         /**
2461          * @param av1 an array (guaranteed)
2462          * @param av2 any object
2463          * @return <code>true</code> if the two arrays are equal
2464          */
2465         private final boolean arrayEquals(Object av1, Object av2) {
2466                 if (av2 == null)
2467                         return false;
2468                 Class<?> c1 = av1.getClass().getComponentType();
2469                 Class<?> c2 = av2.getClass().getComponentType();
2470                 if (c2 == null || !c1.equals(c2))
2471                         return false;
2472                 boolean p1 = c1.isPrimitive();
2473                 boolean p2 = c2.isPrimitive();
2474                 if (p1 != p2)
2475                         return false;
2476                 if (!p1)
2477                         return Arrays.equals((Object[]) av1, (Object[]) av2);
2478                 if (boolean.class.equals(c1))
2479                         return Arrays.equals((boolean[]) av1, (boolean[]) av2);
2480                 else if (byte.class.equals(c1))
2481                         return Arrays.equals((byte[]) av1, (byte[]) av2);
2482                 else if (int.class.equals(c1))
2483                         return Arrays.equals((int[]) av1, (int[]) av2);
2484                 else if (long.class.equals(c1))
2485                         return Arrays.equals((long[]) av1, (long[]) av2);
2486                 else if (float.class.equals(c1))
2487                         return Arrays.equals((float[]) av1, (float[]) av2);
2488                 else if (double.class.equals(c1))
2489                         return Arrays.equals((double[]) av1, (double[]) av2);
2490                 throw new RuntimeException("??? Contact application querySupport.");
2491         }
2492
2493
2494
2495         final private Object compareTo(ReadGraphImpl graph, final CacheEntry entry, final Object oldValue) {
2496
2497                 try {
2498
2499                         Query query = entry.getQuery();
2500
2501                         if(DebugPolicy.RECOMPUTE) System.out.println("R " + query);
2502
2503                         entry.prepareRecompute(querySupport);
2504                         
2505                         ReadGraphImpl parentGraph = graph.withParent(entry);
2506
2507                         query.recompute(parentGraph, this, entry);
2508
2509                         if(entry.isExcepted()) return ListenerEntry.NO_VALUE;
2510
2511                         Object newValue = entry.getResult();
2512
2513                         if (ListenerEntry.NO_VALUE == oldValue) {
2514                                 if(DebugPolicy.CHANGES) {
2515                                         System.out.println("C " + query);
2516                                         System.out.println("- " + oldValue);
2517                                         System.out.println("- " + newValue);
2518                                 }
2519                                 return newValue;
2520                         }
2521
2522                         boolean changed = false;
2523
2524                         if (newValue != null) {
2525                                 if (newValue.getClass().isArray()) {
2526                                         changed = !arrayEquals(newValue, oldValue);
2527                                 } else {
2528                                         changed = !newValue.equals(oldValue);
2529                                 }
2530                         } else
2531                                 changed = (oldValue != null);
2532
2533                         if(DebugPolicy.CHANGES && changed) {
2534                                 System.out.println("C " + query);
2535                                 System.out.println("- " + oldValue);
2536                                 System.out.println("- " + newValue);
2537                         }
2538
2539                         return changed ? newValue : ListenerEntry.NOT_CHANGED;
2540
2541                 } catch (Throwable t) {
2542
2543                         Logger.defaultLogError(t);
2544                         entry.except(t);
2545                         return ListenerEntry.NO_VALUE;
2546
2547                 }
2548
2549         }
2550
2551         public boolean hasScheduledUpdates() {
2552                 return !scheduledListeners.isEmpty();
2553         }
2554
2555         public void performScheduledUpdates(WriteGraphImpl graph) {
2556
2557                 assert (!updating);
2558                 assert (!collecting);
2559                 assert (!firingListeners);
2560
2561                 firingListeners = true;
2562
2563                 try {
2564
2565                         // Performing may cause further events to be scheduled.
2566                         while (!scheduledListeners.isEmpty()) {
2567
2568 //                              graph.restart();
2569 //                              graph.state.barrier.inc();
2570
2571                                 // Clone current events to make new entries possible during
2572                                 // firing.
2573                                 THashSet<ListenerEntry> entries = scheduledListeners;
2574                                 scheduledListeners = new THashSet<ListenerEntry>();
2575
2576                                 ArrayList<ListenerEntry> schedule = new ArrayList<ListenerEntry>();
2577
2578                                 for (ListenerEntry listenerEntry : entries) {
2579
2580                                         if (pruneListener(listenerEntry)) {
2581                                                 if(DebugPolicy.LISTENER) System.out.println("Pruned " + listenerEntry.procedure);
2582                                                 continue;
2583                                         }
2584
2585                                         final CacheEntry entry = listenerEntry.entry;
2586                                         assert (entry != null);
2587
2588                                         Object newValue = compareTo(graph, entry, listenerEntry.getLastKnown());
2589
2590                                         if (newValue != ListenerEntry.NOT_CHANGED) {
2591                                                 if(DebugPolicy.LISTENER)
2592                                                         System.out.println("Add to schedule " + listenerEntry.procedure + " with " + newValue);
2593                                                 schedule.add(listenerEntry);
2594                                                 listenerEntry.setLastKnown(entry.getResult());
2595                                         }
2596
2597                                 }
2598
2599                                 for(ListenerEntry listenerEntry : schedule) {
2600                                         final CacheEntry entry = listenerEntry.entry;
2601                                         if(DebugPolicy.LISTENER)
2602                                                 System.out.println("Firing " + listenerEntry.procedure);
2603                                         try {
2604                                                 if(DebugPolicy.LISTENER)
2605                                                         System.out.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry);
2606                                                 entry.performFromCache(graph, this, listenerEntry.procedure);
2607                                         } catch (Throwable t) {
2608                                                 t.printStackTrace();
2609                                         }
2610                                 }
2611
2612 //                              graph.state.barrier.dec();
2613 //                              graph.waitAsync(null);
2614 //                              graph.state.barrier.assertReady();
2615
2616                         }
2617
2618                 } finally {
2619                         firingListeners = false;
2620                 }
2621
2622         }
2623
2624         /**
2625          * 
2626          * @return true if this entry still has listeners
2627          */
2628         public boolean update(final ReadGraphImpl graph, final CacheEntry entry) {
2629
2630                 assert (!collecting);
2631                 assert (!updating);
2632                 updating = true;
2633
2634                 boolean hadListeners = false;
2635                 boolean listenersUnknown = false;
2636
2637                 try {
2638
2639                         assert(entry != null);
2640                         LinkedList<UpdateEntry> todo = new LinkedList<UpdateEntry>();
2641                         IdentityHashMap<CacheEntry, CacheEntry> immediates = new IdentityHashMap<CacheEntry, CacheEntry>();
2642                         todo.add(new UpdateEntry(null, entry, 0));
2643
2644                         while(true) {
2645
2646                                 // Walk the tree and collect immediate updates
2647                                 while (!todo.isEmpty()) {
2648                                         UpdateEntry e = todo.pop();
2649                                         hadListeners |= updateQuery(e, todo, immediates);
2650                                 }
2651
2652                                 if(immediates.isEmpty()) break;
2653
2654                                 // Evaluate all immediate updates and collect parents to update
2655                                 for(CacheEntry immediate : immediates.values()) {
2656
2657                                         if(immediate.isDiscarded()) {
2658                                                 continue;
2659                                         }
2660
2661                                         if(immediate.isExcepted()) {
2662
2663                                                 Object newValue = compareTo(graph, immediate, ListenerEntry.NO_VALUE);
2664                                                 if (newValue != ListenerEntry.NOT_CHANGED)
2665                                                         updateParents(0, immediate, todo);
2666
2667                                         } else {
2668
2669                                                 Object oldValue = immediate.getResult();
2670                                                 Object newValue = compareTo(graph, immediate, oldValue);
2671
2672                                                 if (newValue != ListenerEntry.NOT_CHANGED) {
2673                                                         updateParents(0, immediate, todo);
2674                                                 } else {
2675                                                         // If not changed, keep the old value
2676                                                         immediate.setResult(oldValue);
2677                                                         listenersUnknown = true;
2678                                                 }
2679
2680                                         }
2681
2682                                 }
2683                                 immediates.clear();
2684
2685                         }
2686
2687                 } catch (Throwable t) {
2688                         Logger.defaultLogError(t);
2689                 }
2690
2691                 assert (updating);
2692                 updating = false;
2693
2694                 return hadListeners | listenersUnknown;
2695
2696         }
2697
2698         volatile public boolean dirty = false;
2699
2700         private ObjectUpdateSet scheduledObjectUpdates = new ObjectUpdateSet();
2701         private ValueUpdateSet scheduledValueUpdates = new ValueUpdateSet();
2702         private ValueUpdateSet scheduledInvalidates = new ValueUpdateSet();
2703         // Maybe use a mutex from util.concurrent?
2704         private Object primitiveUpdateLock = new Object();
2705         private THashSet scheduledPrimitiveUpdates = new THashSet();
2706
2707         public void performDirtyUpdates(final ReadGraphImpl graph) {
2708
2709                 dirty = false;
2710                 lastInvalidate = 0;
2711
2712                 if (Development.DEVELOPMENT) {
2713                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2714                                 System.err.println("== Query update ==");
2715                         }
2716                 }
2717
2718                 // Special case - one statement
2719                 if(scheduledObjectUpdates.size() == 1 && scheduledValueUpdates.size() == 0 && scheduledPrimitiveUpdates.size() == 0 && scheduledInvalidates.size() == 0) {
2720
2721                         long arg0 = scheduledObjectUpdates.getFirst();
2722
2723                         final int subject = (int)(arg0 >>> 32);
2724                         final int predicate = (int)(arg0 & 0xffffffff);
2725
2726                         for(Objects o : Objects.entries(QueryProcessor.this, subject)) update(graph, o);
2727                         for(DirectObjects o : DirectObjects.entries(QueryProcessor.this, subject)) update(graph, o);
2728                         for(Statements o : Statements.entries(QueryProcessor.this, subject)) update(graph, o);
2729
2730                         if(predicate == instanceOf || predicate == inherits || predicate == subrelationOf) {
2731                                 PrincipalTypes principalTypes = PrincipalTypes.entry(QueryProcessor.this, subject);
2732                                 if(principalTypes != null) update(graph, principalTypes);
2733                                 Types types = Types.entry(QueryProcessor.this, subject);
2734                                 if(types != null) update(graph, types);
2735                         }
2736
2737                         if(predicate == subrelationOf) {
2738                                 SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, subject);
2739                                 if(superRelations != null) update(graph, superRelations);
2740                         }
2741
2742                         DirectPredicates dp = DirectPredicates.entry(QueryProcessor.this, subject);
2743                         if(dp != null) update(graph, dp);
2744                         OrderedSet os = OrderedSet.entry(QueryProcessor.this, predicate);
2745                         if(os != null) update(graph, os);
2746
2747                         scheduledObjectUpdates.clear();
2748                         return;
2749
2750                 }
2751
2752                 // Special case - one value
2753                 if(scheduledObjectUpdates.size() == 0 && scheduledValueUpdates.size() == 1 && scheduledPrimitiveUpdates.size() == 0 && scheduledInvalidates.size() == 0) {
2754
2755                         int arg0 = scheduledValueUpdates.getFirst();
2756
2757                         ValueQuery valueQuery = ValueQuery.entry(QueryProcessor.this, arg0);
2758                         if(valueQuery != null) update(graph, valueQuery);
2759
2760                         scheduledValueUpdates.clear();
2761                         return;
2762
2763                 }
2764
2765                 final TIntHashSet predicates = new TIntHashSet();
2766                 final TIntHashSet orderedSets = new TIntHashSet();
2767
2768                 THashSet primitiveUpdates;
2769                 synchronized (primitiveUpdateLock) {
2770                         primitiveUpdates = scheduledPrimitiveUpdates;
2771                         scheduledPrimitiveUpdates = new THashSet();
2772                 }
2773
2774                 primitiveUpdates.forEach(new TObjectProcedure() {
2775
2776                         @Override
2777                         public boolean execute(Object arg0) {
2778
2779                                 ExternalReadEntry query = (ExternalReadEntry)externalReadMap.get(arg0);
2780                                 if (query != null) {
2781                                         boolean listening = update(graph, query);
2782                                         if (!listening && !query.hasParents()) {
2783                                                 externalReadMap.remove(arg0);
2784                                                 query.discard();
2785                                         }
2786                                 }
2787                                 return true;
2788                         }
2789
2790                 });
2791
2792                 scheduledValueUpdates.forEach(new TIntProcedure() {
2793
2794                         @Override
2795                         public boolean execute(int arg0) {
2796                                 ValueQuery valueQuery = ValueQuery.entry(QueryProcessor.this, arg0);
2797                                 if(valueQuery != null) update(graph, valueQuery);
2798                                 return true;
2799                         }
2800
2801                 });
2802
2803                 scheduledInvalidates.forEach(new TIntProcedure() {
2804
2805                         @Override
2806                         public boolean execute(int resource) {
2807                                 
2808                                 ValueQuery valueQuery = ValueQuery.entry(QueryProcessor.this, resource);
2809                                 if(valueQuery != null) update(graph, valueQuery);
2810                                 
2811                                 PrincipalTypes principalTypes = PrincipalTypes.entry(QueryProcessor.this, resource);
2812                                 if(principalTypes != null) update(graph, principalTypes);
2813                                 Types types = Types.entry(QueryProcessor.this, resource);
2814                                 if(types != null) update(graph, types);
2815
2816                                 SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, resource);
2817                                 if(superRelations != null) update(graph, superRelations);
2818
2819                                 predicates.add(resource);
2820                                 
2821                                 return true;
2822                         }
2823
2824                 });
2825
2826                 scheduledObjectUpdates.forEach(new TLongProcedure() {
2827
2828                         @Override
2829                         public boolean execute(long arg0) {
2830
2831                                 final int subject = (int)(arg0 >>> 32);
2832                                 final int predicate = (int)(arg0 & 0xffffffff);
2833
2834                                 if(predicate == instanceOf || predicate == inherits || predicate == subrelationOf) {
2835                                         PrincipalTypes principalTypes = PrincipalTypes.entry(QueryProcessor.this, subject);
2836                                         if(principalTypes != null) update(graph, principalTypes);
2837                                         Types types = Types.entry(QueryProcessor.this, subject);
2838                                         if(types != null) update(graph, types);
2839                                 }
2840
2841                                 if(predicate == subrelationOf) {
2842                                         SuperRelations superRelations = SuperRelations.entry(QueryProcessor.this, subject);
2843                                         if(superRelations != null) update(graph, superRelations);
2844                                 }
2845
2846                                 predicates.add(subject);
2847                                 orderedSets.add(predicate);
2848
2849                                 return true;
2850
2851                         }
2852
2853                 });
2854
2855                 predicates.forEach(new TIntProcedure() {
2856
2857                         @Override
2858                         public boolean execute(final int subject) {
2859
2860                                 for(Objects o : Objects.entries(QueryProcessor.this, subject)) update(graph, o);
2861                                 for(DirectObjects o : DirectObjects.entries(QueryProcessor.this, subject)) update(graph, o);
2862                                 for(Statements o : Statements.entries(QueryProcessor.this, subject)) update(graph, o);
2863
2864                                 DirectPredicates entry = DirectPredicates.entry(QueryProcessor.this, subject);
2865                                 if(entry != null) update(graph, entry);
2866
2867                                 return true;
2868
2869                         }
2870
2871                 });
2872
2873                 orderedSets.forEach(new TIntProcedure() {
2874
2875                         @Override
2876                         public boolean execute(int orderedSet) {
2877
2878                                 OrderedSet entry = OrderedSet.entry(QueryProcessor.this, orderedSet);
2879                                 if(entry != null) update(graph, entry);
2880
2881                                 return true;
2882
2883                         }
2884
2885                 });
2886
2887                 //              for (Integer subject : predicates) {
2888                 //                      DirectPredicates entry = DirectPredicates.entry(QueryProcessor.this, subject);
2889                 //                      if(entry != null) update(graph, entry);
2890                 //              }
2891
2892
2893                 if (Development.DEVELOPMENT) {
2894                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_UPDATE, Bindings.BOOLEAN)) {
2895                                 System.err.println("== Query update ends ==");
2896                         }
2897                 }
2898
2899                 scheduledValueUpdates.clear();
2900                 scheduledObjectUpdates.clear();
2901                 scheduledInvalidates.clear();
2902
2903         }
2904
2905         public void updateValue(final int resource) {
2906                 scheduledValueUpdates.add(resource);
2907                 dirty = true;
2908         }
2909
2910         public void updateStatements(final int resource, final int predicate) {
2911                 scheduledObjectUpdates.add((((long)resource) << 32) + predicate);
2912                 dirty = true;
2913         }
2914         
2915         private int lastInvalidate = 0;
2916         
2917         public void invalidateResource(final int resource) {
2918                 if(lastInvalidate == resource) return;
2919                 scheduledValueUpdates.add(resource);
2920                 lastInvalidate = resource;
2921                 dirty = true;
2922         }
2923
2924         public void updatePrimitive(final ExternalRead primitive) {
2925
2926                 // External reads may be updated from arbitrary threads.
2927                 // Synchronize to prevent race-conditions.
2928                 synchronized (primitiveUpdateLock) {
2929                         scheduledPrimitiveUpdates.add(primitive);
2930                 }
2931                 querySupport.dirtyPrimitives();
2932
2933         }
2934
2935         @Override
2936         public synchronized String toString() {
2937                 return "QueryProvider [size = " + size + ", hits = " + hits + " misses = " + misses + ", updates = " + updates + "]";
2938         }
2939
2940         @Override
2941         protected void doDispose() {
2942
2943                 for(int index = 0; index < THREADS; index++) { 
2944                         executors[index].dispose();
2945                 }
2946
2947                 // First just wait
2948                 for(int i=0;i<100;i++) {
2949
2950                         boolean alive = false;
2951                         for(int index = 0; index < THREADS; index++) { 
2952                                 alive |= executors[index].isAlive();
2953                         }
2954                         if(!alive) return;
2955                         try {
2956                                 Thread.sleep(5);
2957                         } catch (InterruptedException e) {
2958                                 Logger.defaultLogError(e);
2959                         }
2960
2961                 }
2962
2963                 // Then start interrupting
2964                 for(int i=0;i<100;i++) {
2965
2966                         boolean alive = false;
2967                         for(int index = 0; index < THREADS; index++) { 
2968                                 alive |= executors[index].isAlive();
2969                         }
2970                         if(!alive) return;
2971                         for(int index = 0; index < THREADS; index++) {
2972                                 executors[index].interrupt();
2973                         }
2974                 }
2975
2976                 //              // Then just destroy
2977                 //              for(int index = 0; index < THREADS; index++) {
2978                 //                      executors[index].destroy();
2979                 //              }
2980
2981                 for(int index = 0; index < THREADS; index++) {
2982                         try {
2983                                 executors[index].join(5000);
2984                         } catch (InterruptedException e) {
2985                                 Logger.defaultLogError("QueryThread " + index + " will not die.", e);
2986                         }
2987                         executors[index] = null;
2988                 }
2989
2990         }
2991
2992         public int getHits() {
2993                 return hits;
2994         }
2995
2996         public int getMisses() {
2997                 return misses;
2998         }
2999
3000         public int getSize() {
3001                 return size;
3002         }
3003
3004         public Set<Long> getReferencedClusters() {
3005                 HashSet<Long> result = new HashSet<Long>();
3006                 for (CacheEntry entry : objectsMap.values()) {
3007                         Objects query = (Objects) entry.getQuery();
3008                         result.add(querySupport.getClusterId(query.r1()));
3009                 }
3010                 for (CacheEntry entry : directPredicatesMap.values()) {
3011                         DirectPredicates query = (DirectPredicates) entry.getQuery();
3012                         result.add(querySupport.getClusterId(query.id));
3013                 }
3014                 for (CacheEntry entry : valueMap.values()) {
3015                         ValueQuery query = (ValueQuery) entry.getQuery();
3016                         result.add(querySupport.getClusterId(query.id));
3017                 }
3018                 return result;
3019         }
3020
3021         public void assertDone() {
3022         }
3023
3024         CacheCollectionResult allCaches(CacheCollectionResult result) {
3025
3026                 int level = Integer.MAX_VALUE;
3027                 directPredicatesMap.values(level, result);
3028                 principalTypesMap.values(level, result);
3029                 for(CacheEntryBase e : uriToResourceMap.values())
3030                         if(e.getLevel() <= level)
3031                                 result.add(e);
3032                 for(CacheEntryBase e : namespaceIndexMap22.values())
3033                         if(e.getLevel() <= level)
3034                                 result.add(e);
3035                 projectsMap.values(level, result);
3036                 
3037                 relationInfoMap.values(level, result);
3038                 superTypesMap.values(level, result);
3039                 typeHierarchyMap.values(level, result);
3040                 superRelationsMap.values(level, result);
3041                 typesMap.values(level, result);
3042
3043                 valueMap.values(level, result);
3044                 directObjectsMap.values(level, result);
3045                 objectsMap.values(level, result);
3046                 orderedSetMap.values(level, result);
3047                 predicatesMap.values(level, result);
3048
3049                 statementsMap.values(level, result);
3050                 assertedPredicatesMap.values(level, result);
3051                 assertedStatementsMap.values(level, result);
3052                 externalReadMap.values(level, result);
3053                 asyncReadMap.values(level, result);
3054                 
3055                 readMap.values(level, result);
3056                 asyncMultiReadMap.values(level, result);
3057                 multiReadMap.values(level, result);
3058
3059                 return result;
3060
3061         }
3062
3063         public void printDiagnostics() {
3064         }
3065
3066         public void requestCluster(ReadGraphImpl graph, long clusterId, Runnable runnable) {
3067                 querySupport.requestCluster(graph, clusterId, runnable);
3068         }
3069
3070         public int clean() {
3071                 collector.collect(0, Integer.MAX_VALUE);
3072                 return size;
3073         }
3074
3075         public void clean(final Collection<ExternalRead<?>> requests) {
3076                 QueryCollectorSupport collectorSupport = new QueryCollectorSupport() {
3077                         Iterator<ExternalRead<?>> iterator = requests.iterator();
3078                         @Override
3079                         public CacheCollectionResult allCaches() {
3080                                 throw new UnsupportedOperationException();
3081                         }
3082                         @Override
3083                         public CacheEntryBase iterate(int level) {
3084                                 if(iterator.hasNext()) {
3085                                         ExternalRead<?> request = iterator.next();
3086                                         ExternalReadEntry entry = externalReadMap.get(request);
3087                                         if (entry != null) return entry;
3088                                         else return iterate(level);
3089                                 } else {
3090                                         iterator = requests.iterator();
3091                                         return null;
3092                                 }
3093                         }
3094                         @Override
3095                         public void remove() {
3096                                 throw new UnsupportedOperationException();
3097                         }
3098                         @Override
3099                         public void setLevel(CacheEntryBase entry, int level) {
3100                                 throw new UnsupportedOperationException();
3101                         }
3102                         @Override
3103                         public Collection<CacheEntry> getRootList() {
3104                                 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>(requests.size());
3105                                 for (ExternalRead<?> request : requests) {
3106                                         ExternalReadEntry entry = externalReadMap.get(request);
3107                                         if (entry != null)
3108                                                 result.add(entry);
3109                                 }
3110                                 return result;
3111                         }
3112                         @Override
3113                         public int getCurrentSize() {
3114                                 return size;
3115                         }
3116                         @Override
3117                         public int calculateCurrentSize() {
3118                                 // This tells the collector to attempt collecting everything.
3119                                 return Integer.MAX_VALUE;
3120                         }
3121                         @Override
3122                         public boolean start(boolean flush) {
3123                                 return true;
3124                         }
3125                 };
3126                 new QueryCollectorImpl2(this, collectorSupport).collect(0, Integer.MAX_VALUE);
3127         }
3128
3129         public void scanPending() {
3130
3131                 ArrayList<CacheEntry> entries = new ArrayList<CacheEntry>();
3132
3133                 entries.addAll(directPredicatesMap.values());
3134                 entries.addAll(principalTypesMap.values());
3135                 entries.addAll(uriToResourceMap.values());
3136                 entries.addAll(namespaceIndexMap22.values());
3137                 entries.addAll(projectsMap.values());
3138                 entries.addAll(relationInfoMap.values());
3139                 entries.addAll(superTypesMap.values());
3140                 entries.addAll(superRelationsMap.values());
3141                 entries.addAll(typesMap.values());
3142                 entries.addAll(valueMap.values());
3143                 entries.addAll(directObjectsMap.values());
3144                 entries.addAll(objectsMap.values());
3145                 entries.addAll(orderedSetMap.values());
3146                 entries.addAll(predicatesMap.values());
3147                 entries.addAll(orderedSetMap.values());
3148                 entries.addAll(statementsMap.values());
3149                 //                      entries.addAll(assertedObjectsMap.values());
3150                 entries.addAll(assertedPredicatesMap.values());
3151                 entries.addAll(assertedStatementsMap.values());
3152                 entries.addAll(externalReadMap.values());
3153                 entries.addAll(asyncReadMap.values());
3154                 entries.addAll(externalReadMap.values());
3155                 entries.addAll(readMap.values());
3156                 entries.addAll(asyncMultiReadMap.values());
3157                 entries.addAll(multiReadMap.values());
3158                 entries.addAll(readMap.values());
3159                 System.out.println(entries.size() + " entries.");
3160                 for(Object e : entries) {
3161                         if(e instanceof CacheEntry) {
3162                                 CacheEntry en = (CacheEntry)e;
3163                                 if(en.isPending()) System.out.println("pending " + e);
3164                                 if(en.isExcepted()) System.out.println("excepted " + e);
3165                                 if(en.isDiscarded()) System.out.println("discarded " + e);
3166                                 if(en.isRefuted()) System.out.println("refuted " + e);
3167                                 if(en.isFresh()) System.out.println("fresh " + e);
3168                         } else {
3169                                 //System.out.println("Unknown object " + e);
3170                         }
3171                 }
3172
3173         }
3174
3175         public ReadGraphImpl graphForVirtualRequest() {
3176                 return ReadGraphImpl.createAsync(this);
3177         }
3178
3179         
3180         private HashMap<Resource, Class<?>> builtinValues;
3181         
3182         public Class<?> getBuiltinValue(Resource r) {
3183                 if(builtinValues == null) initBuiltinValues();
3184                 return builtinValues.get(r);
3185         }
3186
3187         Exception callerException = null;
3188
3189         public interface AsyncBarrier {
3190                 public void inc(); 
3191                 public void dec();
3192                 //        public void inc(String debug); 
3193                 //        public void dec(String debug);
3194         }
3195
3196 //      final public QueryProcessor processor;
3197 //      final public QuerySupport support;
3198
3199         //    boolean disposed = false;
3200
3201         private void initBuiltinValues() {
3202
3203                 Layer0 b = getSession().peekService(Layer0.class);
3204                 if(b == null) return;
3205
3206                 builtinValues = new HashMap<Resource, Class<?>>();
3207
3208                 builtinValues.put(b.String, String.class);
3209                 builtinValues.put(b.Double, Double.class);
3210                 builtinValues.put(b.Float, Float.class);
3211                 builtinValues.put(b.Long, Long.class);
3212                 builtinValues.put(b.Integer, Integer.class);
3213                 builtinValues.put(b.Byte, Byte.class);
3214                 builtinValues.put(b.Boolean, Boolean.class);
3215
3216                 builtinValues.put(b.StringArray, String[].class);
3217                 builtinValues.put(b.DoubleArray, double[].class);
3218                 builtinValues.put(b.FloatArray, float[].class);
3219                 builtinValues.put(b.LongArray, long[].class);
3220                 builtinValues.put(b.IntegerArray, int[].class);
3221                 builtinValues.put(b.ByteArray, byte[].class);
3222                 builtinValues.put(b.BooleanArray, boolean[].class);
3223
3224         }
3225
3226 //      public ReadGraphSupportImpl(final QueryProcessor provider2) {
3227 //
3228 //              if (null == provider2) {
3229 //                      this.processor = null;
3230 //                      support = null;
3231 //                      return;
3232 //              }
3233 //              this.processor = provider2;
3234 //              support = provider2.getCore();
3235 //              initBuiltinValues();
3236 //
3237 //      }
3238
3239 //      final static public ReadGraphSupportImpl basedOn(ReadGraphSupportImpl impl) {
3240 //              return new ReadGraphSupportImpl(impl.processor);
3241 //      }
3242
3243         @Override
3244         final public Session getSession() {
3245                 return session;
3246         }
3247         
3248         final public ResourceSupport getResourceSupport() {
3249                 return resourceSupport;
3250         }
3251
3252         @Override
3253         final public void forEachPredicate(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3254
3255                 assert(subject != null);
3256                 assert(procedure != null);
3257
3258                 final ListenerBase listener = getListenerBase(procedure);
3259
3260                 IntProcedure ip = new IntProcedure() {
3261
3262                         AtomicBoolean first = new AtomicBoolean(true);
3263
3264                         @Override
3265                         public void execute(ReadGraphImpl graph, int i) {
3266                                 try {
3267                                         if(first.get()) {
3268                                                 procedure.execute(graph, querySupport.getResource(i));
3269                                         } else {
3270                                                 procedure.execute(impl.newRestart(graph), querySupport.getResource(i));
3271                                         }
3272                                 } catch (Throwable t2) {
3273                                         Logger.defaultLogError(t2);
3274                                 }
3275                         }
3276
3277                         @Override
3278                         public void finished(ReadGraphImpl graph) {
3279                                 try {
3280                                         if(first.compareAndSet(true, false)) {
3281                                                 procedure.finished(graph);
3282 //                                              impl.state.barrier.dec(this);
3283                                         } else {
3284                                                 procedure.finished(impl.newRestart(graph));
3285                                         }
3286
3287                                 } catch (Throwable t2) {
3288                                         Logger.defaultLogError(t2);
3289                                 }
3290                         }
3291
3292                         @Override
3293                         public void exception(ReadGraphImpl graph, Throwable t) {
3294                                 try {
3295                                         if(first.compareAndSet(true, false)) {
3296                                                 procedure.exception(graph, t);
3297 //                                              impl.state.barrier.dec(this);
3298                                         } else {
3299                                                 procedure.exception(impl.newRestart(graph), t);
3300                                         }
3301                                 } catch (Throwable t2) {
3302                                         Logger.defaultLogError(t2);
3303                                 }
3304                         }
3305
3306                 };
3307
3308                 int sId = querySupport.getId(subject);
3309
3310 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Predicates#" + sId);
3311 //              else impl.state.barrier.inc(null, null);
3312
3313                 Predicates.queryEach(impl, sId, this, impl.parent, listener, ip);
3314
3315         }
3316
3317         @Override
3318         final public void forEachPredicate(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
3319
3320                 assert(subject != null);
3321                 assert(procedure != null);
3322
3323                 final ListenerBase listener = getListenerBase(procedure);
3324
3325 //              impl.state.barrier.inc();
3326
3327                 Predicates.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, new IntProcedure() {
3328
3329                         @Override
3330                         public void execute(ReadGraphImpl graph, int i) {
3331                                 try {
3332                                         procedure.execute(querySupport.getResource(i));
3333                                 } catch (Throwable t2) {
3334                                         Logger.defaultLogError(t2);
3335                                 }
3336                         }
3337
3338                         @Override
3339                         public void finished(ReadGraphImpl graph) {
3340                                 try {
3341                                         procedure.finished();
3342                                 } catch (Throwable t2) {
3343                                         Logger.defaultLogError(t2);
3344                                 }
3345 //                              impl.state.barrier.dec();
3346                         }
3347
3348                         @Override
3349                         public void exception(ReadGraphImpl graph, Throwable t) {
3350                                 try {
3351                                         procedure.exception(t);
3352                                 } catch (Throwable t2) {
3353                                         Logger.defaultLogError(t2);
3354                                 }
3355 //                              impl.state.barrier.dec();
3356                         }
3357
3358                 });
3359
3360         }
3361         
3362         @Override
3363         final public IntSet getPredicates(final ReadGraphImpl impl, final Resource subject) throws Throwable {
3364
3365                 assert(subject != null);
3366                 
3367                 return Predicates.queryEach2(impl, querySupport.getId(subject), this, impl.parent);
3368
3369         }
3370         
3371
3372         @Override
3373         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
3374                         final Resource predicate, final MultiProcedure<Statement> procedure) {
3375
3376                 assert(subject != null);
3377                 assert(predicate != null);
3378                 assert(procedure != null);
3379
3380                 final ListenerBase listener = getListenerBase(procedure);
3381
3382 //              impl.state.barrier.inc();
3383
3384                 Statements.queryEach(impl, querySupport.getId(subject), querySupport.getId(predicate), this, impl.parent, listener, new TripleIntProcedureAdapter() {
3385
3386                         @Override
3387                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
3388                                 try {
3389                                         procedure.execute(querySupport.getStatement(s, p, o));
3390                                 } catch (Throwable t2) {
3391                                         Logger.defaultLogError(t2);
3392                                 }
3393                         }
3394
3395                         @Override
3396                         public void finished(ReadGraphImpl graph) {
3397                                 try {
3398                                         procedure.finished();
3399                                 } catch (Throwable t2) {
3400                                         Logger.defaultLogError(t2);
3401                                 }
3402 //                              impl.state.barrier.dec();
3403                         }
3404
3405                         @Override
3406                         public void exception(ReadGraphImpl graph, Throwable t) {
3407                                 try {
3408                                         procedure.exception(t);
3409                                 } catch (Throwable t2) {
3410                                         Logger.defaultLogError(t2);
3411                                 }
3412 //                              impl.state.barrier.dec();
3413                         }
3414
3415                 });
3416
3417         }
3418
3419         @Override
3420         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
3421                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
3422
3423                 assert(subject != null);
3424                 assert(predicate != null);
3425                 assert(procedure != null);
3426
3427                 final ListenerBase listener = getListenerBase(procedure);
3428
3429                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
3430
3431                         boolean first = true;
3432
3433                         @Override
3434                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
3435                                 try {
3436                                         if(first) {
3437                                                 procedure.execute(graph, querySupport.getStatement(s, p, o));
3438                                         } else {
3439                                                 procedure.execute(impl.newRestart(graph), querySupport.getStatement(s, p, o));
3440                                         }
3441                                 } catch (Throwable t2) {
3442                                         Logger.defaultLogError(t2);
3443                                 }
3444                         }
3445
3446                         @Override
3447                         public void finished(ReadGraphImpl graph) {
3448
3449                                 try {
3450                                         if(first) {
3451                                                 first = false;
3452                                                 procedure.finished(graph);
3453 //                                              impl.state.barrier.dec(this);
3454                                         } else {
3455                                                 procedure.finished(impl.newRestart(graph));
3456                                         }
3457                                 } catch (Throwable t2) {
3458                                         Logger.defaultLogError(t2);
3459                                 }
3460
3461                         }
3462
3463                         @Override
3464                         public void exception(ReadGraphImpl graph, Throwable t) {
3465
3466                                 try {
3467                                         if(first) {
3468                                                 first = false;
3469                                                 procedure.exception(graph, t);
3470 //                                              impl.state.barrier.dec(this);
3471                                         } else {
3472                                                 procedure.exception(impl.newRestart(graph), t);
3473                                         }
3474                                 } catch (Throwable t2) {
3475                                         Logger.defaultLogError(t2);
3476                                 }
3477
3478                         }
3479
3480                 };
3481
3482                 int sId = querySupport.getId(subject);
3483                 int pId = querySupport.getId(predicate);
3484
3485 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
3486 //              else impl.state.barrier.inc(null, null);
3487
3488                 Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
3489
3490         }
3491
3492         @Override
3493         final public void forEachStatement(final ReadGraphImpl impl, final Resource subject,
3494                         final Resource predicate, final StatementProcedure procedure) {
3495
3496                 assert(subject != null);
3497                 assert(predicate != null);
3498                 assert(procedure != null);
3499
3500                 final ListenerBase listener = getListenerBase(procedure);
3501
3502                 TripleIntProcedureAdapter proc = new TripleIntProcedureAdapter() {
3503
3504                         boolean first = true;
3505
3506                         @Override
3507                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
3508                                 try {
3509                                         if(first) {
3510                                                 procedure.execute(graph, s, p, o);
3511                                         } else {
3512                                                 procedure.execute(impl.newRestart(graph), s, p, o);
3513                                         }
3514                                 } catch (Throwable t2) {
3515                                         Logger.defaultLogError(t2);
3516                                 }
3517                         }
3518
3519                         @Override
3520                         public void finished(ReadGraphImpl graph) {
3521
3522                                 try {
3523                                         if(first) {
3524                                                 first = false;
3525                                                 procedure.finished(graph);
3526 //                                              impl.state.barrier.dec(this);
3527                                         } else {
3528                                                 procedure.finished(impl.newRestart(graph));
3529                                         }
3530                                 } catch (Throwable t2) {
3531                                         Logger.defaultLogError(t2);
3532                                 }
3533
3534                         }
3535
3536                         @Override
3537                         public void exception(ReadGraphImpl graph, Throwable t) {
3538
3539                                 try {
3540                                         if(first) {
3541                                                 first = false;
3542                                                 procedure.exception(graph, t);
3543 //                                              impl.state.barrier.dec(this);
3544                                         } else {
3545                                                 procedure.exception(impl.newRestart(graph), t);
3546                                         }
3547                                 } catch (Throwable t2) {
3548                                         Logger.defaultLogError(t2);
3549                                 }
3550
3551                         }
3552
3553                 };
3554
3555                 int sId = querySupport.getId(subject);
3556                 int pId = querySupport.getId(predicate);
3557
3558 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#Statements" + sId + "#" + pId);
3559 //              else impl.state.barrier.inc(null, null);
3560
3561                 Statements.queryEach(impl, sId, pId, this, impl.parent, listener, proc);
3562
3563         }
3564         
3565         @Override
3566         final public void forStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
3567
3568                 assert(subject != null);
3569                 assert(predicate != null);
3570                 assert(procedure != null);
3571
3572                 forEachStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
3573
3574                         private Set<Statement> current = null;
3575                         private Set<Statement> run = new HashSet<Statement>();
3576
3577                         @Override
3578                         public void execute(AsyncReadGraph graph, Statement result) {
3579
3580                                 boolean found = false;
3581
3582                                 if(current != null) {
3583
3584                                         found = current.remove(result);
3585
3586                                 }
3587
3588                                 if(!found) procedure.add(graph, result);
3589
3590                                 run.add(result);
3591
3592                         }
3593
3594                         @Override
3595                         public void finished(AsyncReadGraph graph) {
3596
3597                                 if(current != null) { 
3598                                         for(Statement r : current) procedure.remove(graph, r);
3599                                 }
3600
3601                                 current = run;
3602
3603                                 run = new HashSet<Statement>();
3604
3605                         }
3606
3607                         @Override
3608                         public void exception(AsyncReadGraph graph, Throwable t) {
3609                                 procedure.exception(graph, t);
3610                         }
3611
3612                         @Override
3613                         public boolean isDisposed() {
3614                                 return procedure.isDisposed();
3615                         }
3616
3617                 });
3618
3619         }
3620
3621         @Override
3622         final public void forEachAssertedStatement(final ReadGraphImpl impl, final Resource subject,
3623                         final Resource predicate, final AsyncMultiProcedure<Statement> procedure) {
3624
3625                 assert(subject != null);
3626                 assert(predicate != null);
3627                 assert(procedure != null);
3628
3629                 final ListenerBase listener = getListenerBase(procedure);
3630
3631 //              impl.state.barrier.inc();
3632
3633                 AssertedStatements.queryEach(impl, querySupport.getId(subject), querySupport.getId(predicate), this, impl.parent, listener, new TripleIntProcedureAdapter() {
3634
3635                         @Override
3636                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
3637                                 try {
3638                                         procedure.execute(graph, querySupport.getStatement(s, p, o));
3639                                 } catch (Throwable t2) {
3640                                         Logger.defaultLogError(t2);
3641                                 }
3642                         }
3643
3644                         @Override
3645                         public void finished(ReadGraphImpl graph) {
3646                                 try {
3647                                         procedure.finished(graph);
3648                                 } catch (Throwable t2) {
3649                                         Logger.defaultLogError(t2);
3650                                 }
3651 //                              impl.state.barrier.dec();
3652                         }
3653
3654                         @Override
3655                         public void exception(ReadGraphImpl graph, Throwable t) {
3656                                 try {
3657                                         procedure.exception(graph, t);
3658                                 } catch (Throwable t2) {
3659                                         Logger.defaultLogError(t2);
3660                                 }
3661 //                              impl.state.barrier.dec();
3662                         }
3663
3664                 });
3665
3666         }
3667
3668         private static ListenerBase getListenerBase(Object procedure) {
3669                 if(procedure instanceof ListenerBase) return (ListenerBase)procedure;
3670                 else return null;
3671         }
3672
3673         @Override
3674         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final MultiProcedure<Resource> procedure) {
3675
3676                 assert(subject != null);
3677                 assert(predicate != null);
3678                 assert(procedure != null);
3679
3680                 final ListenerBase listener = getListenerBase(procedure);
3681
3682 //              impl.state.barrier.inc();
3683
3684                 Objects.runner(impl, querySupport.getId(subject), querySupport.getId(predicate), impl.parent, listener, new IntProcedure() {
3685
3686                         @Override
3687                         public void execute(ReadGraphImpl graph, int i) {
3688                                 try {
3689                                         procedure.execute(querySupport.getResource(i));
3690                                 } catch (Throwable t2) {
3691                                         Logger.defaultLogError(t2);
3692                                 }
3693                         }
3694
3695                         @Override
3696                         public void finished(ReadGraphImpl graph) {
3697                                 try {
3698                                         procedure.finished();
3699                                 } catch (Throwable t2) {
3700                                         Logger.defaultLogError(t2);
3701                                 }
3702 //                              impl.state.barrier.dec();
3703                         }
3704
3705                         @Override
3706                         public void exception(ReadGraphImpl graph, Throwable t) {
3707                                 System.out.println("forEachObject exception " + t);
3708                                 try {
3709                                         procedure.exception(t);
3710                                 } catch (Throwable t2) {
3711                                         Logger.defaultLogError(t2);
3712                                 }
3713 //                              impl.state.barrier.dec();
3714                         }
3715
3716                 });
3717
3718         }
3719
3720
3721 //      @Override
3722 //      final public void forEachDirectObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
3723 //
3724 //              assert(subject != null);
3725 //              assert(predicate != null);
3726 //              assert(procedure != null);
3727 //
3728 //              final ListenerBase listener = getListenerBase(procedure);
3729 //
3730 //              int sId = querySupport.getId(subject);
3731 //              int pId = querySupport.getId(predicate);
3732 //
3733 //              MultiIntProcedure proc = new MultiIntProcedure(procedure, impl, support);
3734 //
3735 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(proc, "#DirectObjects" + sId + "#" + pId);
3736 //              else impl.state.barrier.inc(null, null);
3737 //
3738 //              //        final Exception caller = new Exception();
3739 //
3740 //              //        final Pair<Exception, Exception> exceptions = Pair.make(callerException, new Exception());
3741 //
3742 //              DirectObjects.queryEach(impl, sId, pId, processor, impl.parent, listener, proc);
3743 //
3744 //      }
3745
3746         @Override
3747         final public void forEachDirectPredicate(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
3748
3749                 assert(subject != null);
3750                 assert(procedure != null);
3751
3752                 final ListenerBase listener = getListenerBase(procedure);
3753
3754                 MultiIntProcedure proc = new MultiIntProcedure(procedure, impl, querySupport);
3755
3756                 int sId = querySupport.getId(subject);
3757
3758 //              if(AsyncBarrierImpl.BOOKKEEPING)  impl.state.barrier.inc(proc, "#DirectPredicates" + sId);
3759 //              else impl.state.barrier.inc(null, null);
3760
3761                 DirectPredicates.queryEach(impl, sId, this, impl.parent, listener, proc);
3762
3763         }
3764
3765         @Override
3766         final public void forEachDirectStatement(final ReadGraphImpl impl, final Resource subject, final Procedure<DirectStatements> procedure) {
3767
3768                 assert(subject != null);
3769                 assert(procedure != null);
3770
3771                 final ListenerBase listener = getListenerBase(procedure);
3772
3773                 org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
3774
3775         }
3776
3777         @Override
3778         final public void forEachDirectStatement(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<DirectStatements> procedure, boolean ignoreVirtual) {
3779
3780                 assert(subject != null);
3781                 assert(procedure != null);
3782
3783                 final ListenerBase listener = getListenerBase(procedure);
3784
3785                 org.simantics.db.impl.query.DirectStatements.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure, ignoreVirtual);
3786
3787         }
3788
3789         private static final Resource INVALID_RESOURCE = new ResourceImpl(null, Integer.MIN_VALUE);
3790
3791         @Override
3792         final public void forPossibleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Resource> procedure) {
3793
3794                 forEachObject(impl, subject, predicate, new AsyncMultiProcedure<Resource>() {
3795
3796                         private Resource single = null;
3797
3798                         @Override
3799                         public synchronized void execute(AsyncReadGraph graph, Resource result) {
3800                                 if(single == null) {
3801                                         single = result;
3802                                 } else {
3803                                         single = INVALID_RESOURCE;
3804                                 }
3805                         }
3806
3807                         @Override
3808                         public synchronized void finished(AsyncReadGraph graph) {
3809                                 if(single == null || single == INVALID_RESOURCE) procedure.execute(graph, null);
3810                                 else procedure.execute(graph, single);
3811                         }
3812
3813                         @Override
3814                         public synchronized void exception(AsyncReadGraph graph, Throwable throwable) {
3815                                 procedure.exception(graph, throwable);
3816                         }
3817
3818                 });
3819
3820         }
3821
3822         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final ListenerBase listener, final IntProcedure procedure) {
3823                 
3824                 final int sId = querySupport.getId(subject);
3825                 final int pId = querySupport.getId(predicate);
3826
3827                 Objects.runner(impl, sId, pId, impl.parent, listener, procedure);
3828                 
3829         }
3830         
3831         final public int getSingleObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate) throws DatabaseException {
3832
3833         final int sId = querySupport.getId(subject);
3834         final int pId = querySupport.getId(predicate);
3835
3836         return Objects.runner2(impl, sId, pId, impl.parent);
3837             
3838         }
3839
3840         final public void forEachObject(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
3841
3842                 assert(subject != null);
3843                 assert(predicate != null);
3844
3845                 final ListenerBase listener = getListenerBase(procedure);
3846
3847                 if(impl.parent != null || listener != null) {
3848
3849                         IntProcedure ip = new IntProcedure() {
3850
3851                                 AtomicBoolean first = new AtomicBoolean(true);
3852
3853                                 @Override
3854                                 public void execute(ReadGraphImpl graph, int i) {
3855                                         try {
3856                                                 if(first.get()) {
3857                                                         procedure.execute(impl, querySupport.getResource(i));
3858                                                 } else {
3859                                                         procedure.execute(impl.newRestart(graph), querySupport.getResource(i));
3860                                                 }
3861                                         } catch (Throwable t2) {
3862                                                 Logger.defaultLogError(t2);
3863                                         }
3864
3865                                 }
3866
3867                                 @Override
3868                                 public void finished(ReadGraphImpl graph) {
3869                                         try {
3870                                                 if(first.compareAndSet(true, false)) {
3871                                                         procedure.finished(impl);
3872 //                                                      impl.state.barrier.dec(this);
3873                                                 } else {
3874                                                         procedure.finished(impl.newRestart(graph));
3875                                                 }
3876                                         } catch (Throwable t2) {
3877                                                 Logger.defaultLogError(t2);
3878                                         }
3879                                 }
3880
3881                                 @Override
3882                                 public void exception(ReadGraphImpl graph, Throwable t) {
3883                                         try {
3884                                                 procedure.exception(graph, t);
3885                                         } catch (Throwable t2) {
3886                                                 Logger.defaultLogError(t2);
3887                                         }
3888 //                                      impl.state.barrier.dec(this);
3889                                 }
3890
3891                                 @Override
3892                                 public String toString() {
3893                                         return "forEachObject with " + procedure;
3894                                 }
3895
3896                         };
3897
3898 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Objects" + subject + "#" + predicate);
3899 //                      else impl.state.barrier.inc(null, null);
3900
3901                         forEachObject(impl, subject, predicate, listener, ip);
3902
3903                 } else {
3904
3905                         IntProcedure ip = new IntProcedure() {
3906
3907                                 @Override
3908                                 public void execute(ReadGraphImpl graph, int i) {
3909                                         procedure.execute(graph, querySupport.getResource(i));
3910                                 }
3911
3912                                 @Override
3913                                 public void finished(ReadGraphImpl graph) {
3914                                         procedure.finished(graph);
3915                                 }
3916
3917                                 @Override
3918                                 public void exception(ReadGraphImpl graph, Throwable t) {
3919                                         procedure.exception(graph, t);
3920                                 }
3921
3922                                 @Override
3923                                 public String toString() {
3924                                         return "forEachObject with " + procedure;
3925                                 }
3926
3927                         };
3928
3929                         forEachObject(impl, subject, predicate, listener, ip);
3930
3931                 }
3932
3933         }
3934
3935         @Override
3936         final public void forObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
3937
3938                 assert(subject != null);
3939                 assert(predicate != null);
3940                 assert(procedure != null);
3941
3942                 forEachObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
3943
3944                         private Set<Resource> current = null;
3945                         private Set<Resource> run = new HashSet<Resource>();
3946
3947                         @Override
3948                         public void execute(AsyncReadGraph graph, Resource result) {
3949
3950                                 boolean found = false;
3951
3952                                 if(current != null) {
3953
3954                                         found = current.remove(result);
3955
3956                                 }
3957
3958                                 if(!found) procedure.add(graph, result);
3959
3960                                 run.add(result);
3961
3962                         }
3963
3964                         @Override
3965                         public void finished(AsyncReadGraph graph) {
3966
3967                                 if(current != null) { 
3968                                         for(Resource r : current) procedure.remove(graph, r);
3969                                 }
3970
3971                                 current = run;
3972
3973                                 run = new HashSet<Resource>();
3974
3975                         }
3976
3977                         @Override
3978                         public boolean isDisposed() {
3979                                 return procedure.isDisposed();
3980                         }
3981
3982                         @Override
3983                         public void exception(AsyncReadGraph graph, Throwable t) {
3984                                 procedure.exception(graph, t);
3985                         }
3986
3987                         @Override
3988                         public String toString() {
3989                                 return "forObjectSet " + procedure;
3990                         }
3991
3992                 });
3993
3994         }
3995
3996         @Override
3997         final public void forPredicateSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
3998
3999                 assert(subject != null);
4000                 assert(procedure != null);
4001
4002                 forEachPredicate(impl, subject, new AsyncMultiListener<Resource>() {
4003
4004                         private Set<Resource> current = null;
4005                         private Set<Resource> run = new HashSet<Resource>();
4006
4007                         @Override
4008                         public void execute(AsyncReadGraph graph, Resource result) {
4009
4010                                 boolean found = false;
4011
4012                                 if(current != null) {
4013
4014                                         found = current.remove(result);
4015
4016                                 }
4017
4018                                 if(!found) procedure.add(graph, result);
4019
4020                                 run.add(result);
4021
4022                         }
4023
4024                         @Override
4025                         public void finished(AsyncReadGraph graph) {
4026
4027                                 if(current != null) { 
4028                                         for(Resource r : current) procedure.remove(graph, r);
4029                                 }
4030
4031                                 current = run;
4032
4033                                 run = new HashSet<Resource>();
4034
4035                         }
4036
4037                         @Override
4038                         public boolean isDisposed() {
4039                                 return procedure.isDisposed();
4040                         }
4041
4042                         @Override
4043                         public void exception(AsyncReadGraph graph, Throwable t) {
4044                                 procedure.exception(graph, t);
4045                         }
4046
4047                         @Override
4048                         public String toString() {
4049                                 return "forPredicateSet " + procedure;
4050                         }
4051
4052                 });
4053
4054         }
4055
4056         @Override
4057         final public void forPrincipalTypeSet(final ReadGraphImpl impl, final Resource subject, final AsyncSetListener<Resource> procedure) {
4058
4059                 assert(subject != null);
4060                 assert(procedure != null);
4061
4062                 forEachPrincipalType(impl, subject, new AsyncMultiListener<Resource>() {
4063
4064                         private Set<Resource> current = null;
4065                         private Set<Resource> run = new HashSet<Resource>();
4066
4067                         @Override
4068                         public void execute(AsyncReadGraph graph, Resource result) {
4069
4070                                 boolean found = false;
4071
4072                                 if(current != null) {
4073
4074                                         found = current.remove(result);
4075
4076                                 }
4077
4078                                 if(!found) procedure.add(graph, result);
4079
4080                                 run.add(result);
4081
4082                         }
4083
4084                         @Override
4085                         public void finished(AsyncReadGraph graph) {
4086
4087                                 if(current != null) { 
4088                                         for(Resource r : current) procedure.remove(graph, r);
4089                                 }
4090
4091                                 current = run;
4092
4093                                 run = new HashSet<Resource>();
4094
4095                         }
4096
4097                         @Override
4098                         public boolean isDisposed() {
4099                                 return procedure.isDisposed();
4100                         }
4101
4102                         @Override
4103                         public void exception(AsyncReadGraph graph, Throwable t) {
4104                                 procedure.exception(graph, t);
4105                         }
4106
4107                         @Override
4108                         public String toString() {
4109                                 return "forPrincipalTypeSet " + procedure;
4110                         }
4111
4112                 });
4113
4114         }
4115
4116         @Override
4117         final public void forAssertedObjectSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Resource> procedure) {
4118
4119                 assert(subject != null);
4120                 assert(predicate != null);
4121                 assert(procedure != null);
4122
4123                 forEachAssertedObject(impl, subject, predicate, new AsyncMultiListener<Resource>() {
4124
4125                         private Set<Resource> current = null;
4126                         private Set<Resource> run = new HashSet<Resource>();
4127
4128                         @Override
4129                         public void execute(AsyncReadGraph graph, Resource result) {
4130
4131                                 boolean found = false;
4132
4133                                 if(current != null) {
4134
4135                                         found = current.remove(result);
4136
4137                                 }
4138
4139                                 if(!found) procedure.add(graph, result);
4140
4141                                 run.add(result);
4142
4143                         }
4144
4145                         @Override
4146                         public void finished(AsyncReadGraph graph) {
4147
4148                                 if(current != null) { 
4149                                         for(Resource r : current) procedure.remove(graph, r);
4150                                 }
4151
4152                                 current = run;
4153
4154                                 run = new HashSet<Resource>();
4155
4156                         }
4157
4158                         @Override
4159                         public boolean isDisposed() {
4160                                 return procedure.isDisposed();
4161                         }
4162
4163                         @Override
4164                         public void exception(AsyncReadGraph graph, Throwable t) {
4165                                 procedure.exception(graph, t);
4166                         }
4167
4168                         @Override
4169                         public String toString() {
4170                                 return "forObjectSet " + procedure;
4171                         }
4172
4173                 });
4174
4175         }
4176
4177         @Override
4178         final public void forAssertedStatementSet(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncSetListener<Statement> procedure) {
4179
4180                 assert(subject != null);
4181                 assert(predicate != null);
4182                 assert(procedure != null);
4183
4184                 forEachAssertedStatement(impl, subject, predicate, new AsyncMultiListener<Statement>() {
4185
4186                         private Set<Statement> current = null;
4187                         private Set<Statement> run = new HashSet<Statement>();
4188
4189                         @Override
4190                         public void execute(AsyncReadGraph graph, Statement result) {
4191
4192                                 boolean found = false;
4193
4194                                 if(current != null) {
4195
4196                                         found = current.remove(result);
4197
4198                                 }
4199
4200                                 if(!found) procedure.add(graph, result);
4201
4202                                 run.add(result);
4203
4204                         }
4205
4206                         @Override
4207                         public void finished(AsyncReadGraph graph) {
4208
4209                                 if(current != null) { 
4210                                         for(Statement s : current) procedure.remove(graph, s);
4211                                 }
4212
4213                                 current = run;
4214
4215                                 run = new HashSet<Statement>();
4216
4217                         }
4218
4219                         @Override
4220                         public boolean isDisposed() {
4221                                 return procedure.isDisposed();
4222                         }
4223
4224                         @Override
4225                         public void exception(AsyncReadGraph graph, Throwable t) {
4226                                 procedure.exception(graph, t);
4227                         }
4228
4229                         @Override
4230                         public String toString() {
4231                                 return "forStatementSet " + procedure;
4232                         }
4233
4234                 });
4235
4236         }
4237
4238         @Override
4239         final public void forEachAssertedObject(final ReadGraphImpl impl, final Resource subject,
4240                         final Resource predicate, final AsyncMultiProcedure<Resource> procedure) {
4241
4242                 assert(subject != null);
4243                 assert(predicate != null);
4244                 assert(procedure != null);
4245
4246                 final ListenerBase listener = getListenerBase(procedure);
4247
4248 //              impl.state.barrier.inc();
4249
4250                 AssertedStatements.queryEach(impl, querySupport.getId(subject), querySupport.getId(predicate), this, impl.parent, listener, new TripleIntProcedure() {
4251
4252                         @Override
4253                         public void execute(ReadGraphImpl graph, int s, int p, int o) {
4254                                 try {
4255                                         procedure.execute(graph, querySupport.getResource(o));
4256                                 } catch (Throwable t2) {
4257                                         Logger.defaultLogError(t2);
4258                                 }
4259                         }
4260
4261                         @Override
4262                         public void finished(ReadGraphImpl graph) {
4263                                 try {               
4264                                         procedure.finished(graph);
4265                                 } catch (Throwable t2) {
4266                                         Logger.defaultLogError(t2);
4267                                 }
4268 //                              impl.state.barrier.dec();
4269                         }
4270
4271                         @Override
4272                         public void exception(ReadGraphImpl graph, Throwable t) {
4273                                 try {
4274                                         procedure.exception(graph, t);
4275                                 } catch (Throwable t2) {
4276                                         Logger.defaultLogError(t2);
4277                                 }
4278 //                              impl.state.barrier.dec();
4279                         }
4280
4281                 });
4282
4283         }
4284
4285         @Override
4286         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
4287
4288                 assert(subject != null);
4289                 assert(procedure != null);
4290
4291                 final ListenerBase listener = getListenerBase(procedure);
4292
4293                 IntProcedure ip = new IntProcedure() {
4294
4295                         @Override
4296                         public void execute(ReadGraphImpl graph, int i) {
4297                                 try {
4298                                         procedure.execute(graph, querySupport.getResource(i));
4299                                 } catch (Throwable t2) {
4300                                         Logger.defaultLogError(t2);
4301                                 }
4302                         }
4303
4304                         @Override
4305                         public void finished(ReadGraphImpl graph) {
4306                                 try {
4307                                         procedure.finished(graph);
4308                                 } catch (Throwable t2) {
4309                                         Logger.defaultLogError(t2);
4310                                 }
4311 //                              impl.state.barrier.dec(this);
4312                         }
4313
4314                         @Override
4315                         public void exception(ReadGraphImpl graph, Throwable t) {
4316                                 try {
4317                                         procedure.exception(graph, t);
4318                                 } catch (Throwable t2) {
4319                                         Logger.defaultLogError(t2);
4320                                 }
4321 //                              impl.state.barrier.dec(this);
4322                         }
4323
4324                 };
4325
4326                 int sId = querySupport.getId(subject);
4327
4328 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#PrincipalTypes#" + sId);
4329 //              else impl.state.barrier.inc(null, null);
4330
4331                 PrincipalTypes.queryEach(impl, sId, this, impl.parent, listener, ip);
4332
4333         }
4334
4335         @Override
4336         final public void forEachPrincipalType(final ReadGraphImpl impl, final Resource subject, final MultiProcedure<Resource> procedure) {
4337
4338                 assert(subject != null);
4339                 assert(procedure != null);
4340
4341                 final ListenerBase listener = getListenerBase(procedure);
4342
4343 //              impl.state.barrier.inc();
4344
4345                 PrincipalTypes.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, new IntProcedure() {
4346
4347                         @Override
4348                         public void execute(ReadGraphImpl graph, int i) {
4349                                 try {
4350                                         procedure.execute(querySupport.getResource(i));
4351                                 } catch (Throwable t2) {
4352                                         Logger.defaultLogError(t2);
4353                                 }
4354                         }
4355
4356                         @Override
4357                         public void finished(ReadGraphImpl graph) {
4358                                 try {
4359                                         procedure.finished();
4360                                 } catch (Throwable t2) {
4361                                         Logger.defaultLogError(t2);
4362                                 }
4363 //                              impl.state.barrier.dec();
4364                         }
4365
4366                         @Override
4367                         public void exception(ReadGraphImpl graph, Throwable t) {
4368                                 try {
4369                                         procedure.exception(t);
4370                                 } catch (Throwable t2) {
4371                                         Logger.defaultLogError(t2);
4372                                 }
4373 //                              impl.state.barrier.dec();
4374                         }
4375
4376                 });
4377
4378         }
4379
4380     final public void forTypes(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
4381
4382         assert(subject != null);
4383         assert(procedure != null);
4384
4385         final ListenerBase listener = getListenerBase(procedure);
4386
4387         InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
4388
4389             AtomicBoolean first = new AtomicBoolean(true);
4390
4391             @Override
4392             public void execute(final ReadGraphImpl graph, IntSet set) {
4393                 try {
4394                     if(first.compareAndSet(true, false)) {
4395                         procedure.execute(graph, set);
4396 //                      impl.state.barrier.dec(this);
4397                     } else {
4398                         procedure.execute(impl.newRestart(graph), set);
4399                     }
4400                 } catch (Throwable t2) {
4401                     Logger.defaultLogError(t2);
4402                 }
4403             }
4404
4405             @Override
4406             public void exception(ReadGraphImpl graph, Throwable t) {
4407                 try {
4408                     if(first.compareAndSet(true, false)) {
4409                         procedure.exception(graph, t);
4410 //                      impl.state.barrier.dec(this);
4411                     } else {
4412                         procedure.exception(impl.newRestart(graph), t);
4413                     }
4414                 } catch (Throwable t2) {
4415                     Logger.defaultLogError(t2);
4416                 }
4417             }
4418
4419         };
4420
4421         int sId = querySupport.getId(subject);
4422
4423 //      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Types" + sId);
4424 //      else impl.state.barrier.inc(null, null);
4425
4426         Types.queryEach(impl, sId, this, impl.parent, listener, ip);
4427
4428     }
4429     
4430         @Override
4431         final public IntSet getTypes(final ReadGraphImpl impl, final Resource subject) throws Throwable {
4432
4433                 assert(subject != null);
4434                 
4435                 return Types.queryEach2(impl, querySupport.getId(subject), this, impl.parent);
4436
4437         }
4438
4439         @Override
4440         final public void forRelationInfo(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<RelationInfo> procedure) {
4441
4442                 assert(subject != null);
4443                 assert(procedure != null);
4444
4445                 final ListenerBase listener = getListenerBase(procedure);
4446
4447 //              impl.state.barrier.inc();
4448
4449                 RelationInfoQuery.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, new InternalProcedure<RelationInfo>() {
4450
4451                         AtomicBoolean first = new AtomicBoolean(true);
4452
4453                         @Override
4454                         public void execute(final ReadGraphImpl graph, RelationInfo set) {
4455                                 try {
4456                                         if(first.compareAndSet(true, false)) {
4457                                                 procedure.execute(graph, set);
4458 //                                              impl.state.barrier.dec();
4459                                         } else {
4460                                                 procedure.execute(impl.newRestart(graph), set);
4461                                         }
4462                                 } catch (Throwable t2) {
4463                                         Logger.defaultLogError(t2);
4464                                 }
4465                         }
4466
4467                         @Override
4468                         public void exception(ReadGraphImpl graph, Throwable t) {
4469                                 try {
4470                                         if(first.compareAndSet(true, false)) {
4471                                                 procedure.exception(graph, t);
4472 //                                              impl.state.barrier.dec("ReadGraphSupportImpl.1353");
4473                                         } else {
4474                                                 procedure.exception(impl.newRestart(graph), t);
4475                                         }
4476                                 } catch (Throwable t2) {
4477                                         Logger.defaultLogError(t2);
4478                                 }
4479                         }
4480
4481                 });
4482
4483         }
4484
4485         @Override
4486         final public void forSupertypes(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
4487
4488                 assert(subject != null);
4489                 assert(procedure != null);
4490
4491                 final ListenerBase listener = getListenerBase(procedure);
4492
4493 //              impl.state.barrier.inc();
4494
4495                 SuperTypes.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, new InternalProcedure<IntSet>() {
4496
4497                         AtomicBoolean first = new AtomicBoolean(true);
4498
4499                         @Override
4500                         public void execute(final ReadGraphImpl graph, IntSet set) {
4501 //                              final HashSet<Resource> result = new HashSet<Resource>();
4502 //                              set.forEach(new TIntProcedure() {
4503 //
4504 //                                      @Override
4505 //                                      public boolean execute(int type) {
4506 //                                              result.add(querySupport.getResource(type));
4507 //                                              return true;
4508 //                                      }
4509 //
4510 //                              });
4511                                 try {
4512                                         if(first.compareAndSet(true, false)) {
4513                                                 procedure.execute(graph, set);
4514 //                                              impl.state.barrier.dec();
4515                                         } else {
4516                                                 procedure.execute(impl.newRestart(graph), set);
4517                                         }
4518                                 } catch (Throwable t2) {
4519                                         Logger.defaultLogError(t2);
4520                                 }
4521                         }
4522
4523                         @Override
4524                         public void exception(ReadGraphImpl graph, Throwable t) {
4525                                 try {
4526                                         if(first.compareAndSet(true, false)) {
4527                                                 procedure.exception(graph, t);
4528 //                                              impl.state.barrier.dec();
4529                                         } else {
4530                                                 procedure.exception(impl.newRestart(graph), t);
4531                                         }
4532                                 } catch (Throwable t2) {
4533                                         Logger.defaultLogError(t2);
4534                                 }
4535                         }
4536
4537                 });
4538
4539         }
4540
4541         @Override
4542         final public void forDirectSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
4543
4544                 assert(subject != null);
4545                 assert(procedure != null);
4546
4547                 final ListenerBase listener = getListenerBase(procedure);
4548
4549                 IntProcedure ip = new IntProcedureAdapter() {
4550
4551                         @Override
4552                         public void execute(final ReadGraphImpl graph, int superRelation) {
4553                                 try {
4554                                         procedure.execute(graph, querySupport.getResource(superRelation));
4555                                 } catch (Throwable t2) {
4556                                         Logger.defaultLogError(t2);
4557                                 }
4558                         }
4559
4560                         @Override
4561                         public void finished(final ReadGraphImpl graph) {
4562                                 try {
4563                                         procedure.finished(graph);
4564                                 } catch (Throwable t2) {
4565                                         Logger.defaultLogError(t2);
4566                                 }
4567 //                              impl.state.barrier.dec(this);
4568                         }
4569
4570
4571                         @Override
4572                         public void exception(ReadGraphImpl graph, Throwable t) {
4573                                 try {
4574                                         procedure.exception(graph, t);
4575                                 } catch (Throwable t2) {
4576                                         Logger.defaultLogError(t2);
4577                                 }
4578 //                              impl.state.barrier.dec(this);
4579                         }
4580
4581                 };
4582
4583                 int sId = querySupport.getId(subject); 
4584
4585 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectSuperRelations#" + sId);
4586 //              else impl.state.barrier.inc(null, null);
4587
4588                 DirectSuperRelations.queryEach(impl, sId, this, impl.parent, listener, ip);
4589
4590         }
4591
4592         @Override
4593         final public void forPossibleSuperrelation(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Resource> procedure) {
4594
4595                 assert(subject != null);
4596                 assert(procedure != null);
4597
4598                 final ListenerBase listener = getListenerBase(procedure);
4599
4600 //              impl.state.barrier.inc();
4601
4602                 PossibleSuperRelation.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, procedure);
4603
4604         }
4605
4606         @Override
4607         final public void forSuperrelations(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Set<Resource>> procedure) {
4608
4609                 assert(subject != null);
4610                 assert(procedure != null);
4611
4612                 final ListenerBase listener = getListenerBase(procedure);
4613
4614                 InternalProcedure<IntSet> ip = new InternalProcedure<IntSet>() {
4615
4616                         @Override
4617                         public void execute(final ReadGraphImpl graph, IntSet set) {
4618 //                              final HashSet<Resource> result = new HashSet<Resource>();
4619 //                              set.forEach(new TIntProcedure() {
4620 //
4621 //                                      @Override
4622 //                                      public boolean execute(int type) {
4623 //                                              result.add(querySupport.getResource(type));
4624 //                                              return true;
4625 //                                      }
4626 //
4627 //                              });
4628                                 try {
4629                                         procedure.execute(graph, set);
4630                                 } catch (Throwable t2) {
4631                                         Logger.defaultLogError(t2);
4632                                 }
4633 //                              impl.state.barrier.dec(this);
4634                         }
4635
4636                         @Override
4637                         public void exception(ReadGraphImpl graph, Throwable t) {
4638                                 try {
4639                                         procedure.exception(graph, t);
4640                                 } catch (Throwable t2) {
4641                                         Logger.defaultLogError(t2);
4642                                 }
4643 //                              impl.state.barrier.dec(this);
4644                         }
4645
4646                 };
4647
4648                 int sId = querySupport.getId(subject);
4649
4650 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#SuperRelations#" + sId);
4651 //              else impl.state.barrier.inc(null, null);
4652
4653                 SuperRelations.queryEach(impl, sId, this, impl.parent, listener, ip);
4654
4655         }
4656
4657         final public byte[] getValue(final ReadGraphImpl impl, final Resource subject) throws DatabaseException {
4658
4659           int sId = querySupport.getId(subject);
4660       return ValueQuery.queryEach(impl, sId, impl.parent);
4661
4662         }
4663
4664         final public byte[] getValue(final ReadGraphImpl impl, final int subject) throws DatabaseException {
4665
4666             return ValueQuery.queryEach(impl, subject, impl.parent);
4667
4668         }
4669
4670         @Override
4671         final public byte[] forValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
4672
4673                 assert(subject != null);
4674
4675                 int sId = querySupport.getId(subject);
4676
4677                 if(procedure != null) {
4678                 
4679                         final ListenerBase listener = getListenerBase(procedure);
4680
4681                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
4682
4683                                 AtomicBoolean first = new AtomicBoolean(true);
4684
4685                                 @Override
4686                                 public void execute(ReadGraphImpl graph, byte[] result) {
4687                                         try {
4688                                                 if(first.compareAndSet(true, false)) {
4689                                                         procedure.execute(graph, result);
4690 //                                                      impl.state.barrier.dec(this);
4691                                                 } else {
4692                                                         procedure.execute(impl.newRestart(graph), result);
4693                                                 }
4694                                         } catch (Throwable t2) {
4695                                                 Logger.defaultLogError(t2);
4696                                         }
4697                                 }
4698
4699                                 @Override
4700                                 public void exception(ReadGraphImpl graph, Throwable t) {
4701                                         try {
4702                                                 if(first.compareAndSet(true, false)) {
4703                                                         procedure.exception(graph, t);
4704 //                                                      impl.state.barrier.dec(this);
4705                                                 } else {
4706                                                         procedure.exception(impl.newRestart(graph), t);
4707                                                 }
4708                                         } catch (Throwable t2) {
4709                                                 Logger.defaultLogError(t2);
4710                                         }
4711                                 }
4712
4713                         };
4714
4715 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
4716 //                      else impl.state.barrier.inc(null, null);
4717
4718                         return ValueQuery.queryEach(impl, sId, impl.parent, listener, ip);
4719
4720                 } else {
4721
4722                         return ValueQuery.queryEach(impl, sId, impl.parent, null, null);
4723                         
4724                 }
4725
4726         }
4727
4728         @Override
4729         final public void forPossibleValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<byte[]> procedure) {
4730
4731                 assert(subject != null);
4732                 assert(procedure != null);
4733
4734                 final ListenerBase listener = getListenerBase(procedure);
4735
4736                 if(impl.parent != null || listener != null) {
4737
4738                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
4739
4740                                 AtomicBoolean first = new AtomicBoolean(true);
4741
4742                                 @Override
4743                                 public void execute(ReadGraphImpl graph, byte[] result) {
4744                                         try {
4745                                                 if(first.compareAndSet(true, false)) {
4746                                                         procedure.execute(graph, result);
4747 //                                                      impl.state.barrier.dec(this);
4748                                                 } else {
4749                                                         procedure.execute(impl.newRestart(graph), result);
4750                                                 }
4751                                         } catch (Throwable t2) {
4752                                                 Logger.defaultLogError(t2);
4753                                         }
4754                                 }
4755
4756                                 @Override
4757                                 public void exception(ReadGraphImpl graph, Throwable t) {
4758                                         try {
4759                                                 if(first.compareAndSet(true, false)) {
4760                                                         procedure.exception(graph, t);
4761 //                                                      impl.state.barrier.dec(this);
4762                                                 } else {
4763                                                         procedure.exception(impl.newRestart(graph), t);
4764                                                 }
4765                                         } catch (Throwable t2) {
4766                                                 Logger.defaultLogError(t2);
4767                                         }
4768                                 }
4769
4770                         };
4771
4772                         int sId = querySupport.getId(subject);
4773
4774 //                      if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#Value" + sId);
4775 //                      else impl.state.barrier.inc(null, null);
4776
4777                         ValueQuery.queryEach(impl, sId, impl.parent, listener, ip);
4778
4779                 } else {
4780
4781                         InternalProcedure<byte[]> ip = new InternalProcedure<byte[]>() {
4782
4783                                 @Override
4784                                 public void execute(ReadGraphImpl graph, byte[] result) {
4785
4786                                         procedure.execute(graph, result);
4787
4788                                 }
4789
4790                                 @Override
4791                                 public void exception(ReadGraphImpl graph, Throwable t) {
4792
4793                                         procedure.exception(graph, t);
4794
4795                                 }
4796
4797                         };
4798
4799                         int sId = querySupport.getId(subject);
4800
4801                         ValueQuery.queryEach(impl, sId, impl.parent, listener, ip);
4802
4803                 }
4804
4805         }
4806
4807         @Override
4808         final public void forInverse(final ReadGraphImpl impl, final Resource relation, final AsyncProcedure<Resource> procedure) {
4809
4810                 assert(relation != null);
4811                 assert(procedure != null);
4812
4813                 final ListenerBase listener = getListenerBase(procedure);
4814
4815                 IntProcedure ip = new IntProcedure() {
4816
4817                         private int result = 0;
4818                         
4819                     final AtomicBoolean found = new AtomicBoolean(false);
4820                     final AtomicBoolean done = new AtomicBoolean(false);
4821
4822                         @Override
4823                         public void finished(ReadGraphImpl graph) {
4824                                 
4825                         // Shall fire exactly once!
4826                         if(done.compareAndSet(false, true)) {
4827                                 try {
4828                                         if(result == 0) {
4829                                                         procedure.exception(graph, new NoInverseException(""));
4830 //                                              impl.state.barrier.dec(this);
4831                                         } else {
4832                                                 procedure.execute(graph, querySupport.getResource(result));
4833 //                                              impl.state.barrier.dec(this);
4834                                         }
4835                                 } catch (Throwable t) {
4836                                         Logger.defaultLogError(t);
4837                                 }
4838                         }
4839                         
4840                         }
4841
4842                         @Override
4843                         public void execute(ReadGraphImpl graph, int i) {
4844                                 
4845                                 if(found.compareAndSet(false, true)) {
4846                                         this.result = i;
4847                                 } else {
4848                                         // Shall fire exactly once!
4849                                         if(done.compareAndSet(false, true)) {
4850                                                 try {
4851                                                         procedure.exception(graph, new ManyObjectsForFunctionalRelationException("Multiple items e.g. " + this.result + " and " + result));
4852 //                                                      impl.state.barrier.dec(this);
4853                                                 } catch (Throwable t) {
4854                                                 Logger.defaultLogError(t);
4855                                                 }
4856                                         }
4857                                 }
4858                                 
4859                         }
4860
4861                         @Override
4862                         public void exception(ReadGraphImpl graph, Throwable t) {
4863                                 // Shall fire exactly once!
4864                                 if(done.compareAndSet(false, true)) {
4865                                         try {
4866                                                 procedure.exception(graph, t);
4867 //                                              impl.state.barrier.dec(this);
4868                                         } catch (Throwable t2) {
4869                                         Logger.defaultLogError(t2);
4870                                         }
4871                                 }
4872                         }
4873
4874                 };
4875
4876                 int sId = querySupport.getId(relation);
4877
4878 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#DirectObjects#" + sId);
4879 //              else impl.state.barrier.inc(null, null);
4880
4881                 Objects.runner(impl, sId, getInverseOf(), impl.parent, listener, ip);
4882
4883         }
4884
4885         @Override
4886         final public void forResource(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
4887
4888                 assert(id != null);
4889                 assert(procedure != null);
4890
4891                 InternalProcedure<Integer> ip = new InternalProcedure<Integer>() {
4892
4893                         @Override
4894                         public void execute(ReadGraphImpl graph, Integer result) {
4895                                 try {
4896                                         procedure.execute(graph, querySupport.getResource(result));
4897                                 } catch (Throwable t2) {
4898                                         Logger.defaultLogError(t2);
4899                                 }
4900 //                              impl.state.barrier.dec(this);
4901                         }   
4902
4903                         @Override
4904                         public void exception(ReadGraphImpl graph, Throwable t) {
4905
4906                                 try {
4907                                         procedure.exception(graph, t);
4908                                 } catch (Throwable t2) {
4909                                         Logger.defaultLogError(t2);
4910                                 }
4911 //                              impl.state.barrier.dec(this);
4912                         }
4913
4914                 };
4915
4916 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "Resource");
4917 //              else impl.state.barrier.inc(null, null);
4918
4919                 forResource(impl, id, impl.parent, ip);
4920
4921         }
4922
4923         @Override
4924         final public void forBuiltin(final ReadGraphImpl impl, final String id, final AsyncProcedure<Resource> procedure) {
4925
4926                 assert(id != null);
4927                 assert(procedure != null);
4928
4929 //              impl.state.barrier.inc();
4930
4931                 forBuiltin(impl, id, impl.parent, new InternalProcedure<Integer>() {
4932
4933                         @Override
4934                         public void execute(ReadGraphImpl graph, Integer result) {
4935                                 try {
4936                                         procedure.execute(graph, querySupport.getResource(result)); 
4937                                 } catch (Throwable t2) {
4938                                         Logger.defaultLogError(t2);
4939                                 }
4940 //                              impl.state.barrier.dec();
4941                         }   
4942
4943                         @Override
4944                         public void exception(ReadGraphImpl graph, Throwable t) {
4945                                 try {
4946                                         procedure.exception(graph, t);
4947                                 } catch (Throwable t2) {
4948                                         Logger.defaultLogError(t2);
4949                                 }
4950 //                              impl.state.barrier.dec();
4951                         }
4952
4953                 });
4954
4955         }
4956
4957         @Override
4958         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
4959
4960                 assert(subject != null);
4961                 assert(procedure != null);
4962
4963                 final ListenerBase listener = getListenerBase(procedure);
4964
4965 //              impl.state.barrier.inc();
4966
4967                 DirectPredicates.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, new IntProcedure() {
4968
4969                         boolean found = false;
4970
4971                         @Override
4972                         public void execute(ReadGraphImpl graph, int object) {
4973                                 found = true;
4974                         }
4975
4976                         @Override
4977                         public void finished(ReadGraphImpl graph) {
4978                                 try {
4979                                         procedure.execute(graph, found);
4980                                 } catch (Throwable t2) {
4981                                         Logger.defaultLogError(t2);
4982                                 }
4983 //                              impl.state.barrier.dec();
4984                         }
4985
4986                         @Override
4987                         public void exception(ReadGraphImpl graph, Throwable t) {
4988                                 try {
4989                                         procedure.exception(graph, t);
4990                                 } catch (Throwable t2) {
4991                                         Logger.defaultLogError(t2);
4992                                 }
4993 //                              impl.state.barrier.dec();
4994                         }
4995
4996                 });
4997
4998         }
4999
5000         @Override
5001         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final AsyncProcedure<Boolean> procedure) {
5002
5003                 assert(subject != null);
5004                 assert(predicate != null);
5005                 assert(procedure != null);
5006
5007                 AsyncMultiProcedure<Resource> ip = new AsyncMultiProcedureAdapter<Resource>() {
5008
5009                         boolean found = false;
5010
5011                         @Override
5012                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
5013                                 found = true;
5014                         }
5015
5016                         @Override
5017                         synchronized public void finished(AsyncReadGraph graph) {
5018                                 try {
5019                                         procedure.execute(graph, found);
5020                                 } catch (Throwable t2) {
5021                                         Logger.defaultLogError(t2);
5022                                 }
5023 //                              impl.state.barrier.dec(this);
5024                         }
5025
5026                         @Override
5027                         public void exception(AsyncReadGraph graph, Throwable t) {
5028                                 try {
5029                                         procedure.exception(graph, t);
5030                                 } catch (Throwable t2) {
5031                                         Logger.defaultLogError(t2);
5032                                 }
5033 //                              impl.state.barrier.dec(this);
5034                         }
5035
5036                 };
5037
5038 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(ip, "#ForEachObject#" + subject + "#" + predicate);
5039 //              else impl.state.barrier.inc(null, null);
5040
5041                 forEachObject(impl, subject, predicate, ip);
5042
5043         }
5044
5045         @Override
5046         final public void forHasStatement(final ReadGraphImpl impl, final Resource subject, final Resource predicate, final Resource object, final AsyncProcedure<Boolean> procedure) {
5047
5048                 assert(subject != null);
5049                 assert(predicate != null);
5050                 assert(procedure != null);
5051
5052 //              impl.state.barrier.inc();
5053
5054                 forEachObject(impl, subject, predicate, new AsyncMultiProcedureAdapter<Resource>() {
5055
5056                         boolean found = false;
5057
5058                         @Override
5059                         synchronized public void execute(AsyncReadGraph graph, Resource resource) {
5060                                 if(resource.equals(object)) found = true;
5061                         }
5062
5063                         @Override
5064                         synchronized public void finished(AsyncReadGraph graph) {
5065                                 try {
5066                                         procedure.execute(graph, found);
5067                                 } catch (Throwable t2) {
5068                                         Logger.defaultLogError(t2);
5069                                 }
5070 //                              impl.state.barrier.dec();
5071                         }
5072
5073                         @Override
5074                         public void exception(AsyncReadGraph graph, Throwable t) {
5075                                 try {
5076                                         procedure.exception(graph, t);
5077                                 } catch (Throwable t2) {
5078                                         Logger.defaultLogError(t2);
5079                                 }
5080 //                              impl.state.barrier.dec();
5081                         }
5082
5083                 });
5084
5085         }
5086
5087         @Override
5088         final public void forHasValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure<Boolean> procedure) {
5089
5090                 assert(subject != null);
5091                 assert(procedure != null);
5092
5093                 final ListenerBase listener = getListenerBase(procedure);
5094
5095 //              impl.state.barrier.inc();
5096
5097                 ValueQuery.queryEach(impl, querySupport.getId(subject), impl.parent, listener, new InternalProcedure<byte[]>() {
5098
5099                         @Override
5100                         public void execute(ReadGraphImpl graph, byte[] object) {
5101                                 boolean result = object != null;
5102                                 try {
5103                                         procedure.execute(graph, result);
5104                                 } catch (Throwable t2) {
5105                                         Logger.defaultLogError(t2);
5106                                 }
5107 //                              impl.state.barrier.dec();
5108                         }
5109
5110                         @Override
5111                         public void exception(ReadGraphImpl graph, Throwable t) {
5112                                 try {
5113                                         procedure.exception(graph, t);
5114                                 } catch (Throwable t2) {
5115                                         Logger.defaultLogError(t2);
5116                                 }
5117 //                              impl.state.barrier.dec();
5118                         }
5119
5120                 });
5121
5122         }
5123
5124         @Override
5125         final public void forOrderedSet(final ReadGraphImpl impl, final Resource subject, final AsyncMultiProcedure<Resource> procedure) {
5126
5127                 assert(subject != null);
5128                 assert(procedure != null);
5129
5130                 final ListenerBase listener = getListenerBase(procedure);
5131
5132 //              impl.state.barrier.inc();
5133
5134                 OrderedSet.queryEach(impl, querySupport.getId(subject), this, impl.parent, listener, new IntProcedure() {
5135
5136                         @Override
5137                         public void exception(ReadGraphImpl graph, Throwable t) {
5138                                 try {
5139                                         procedure.exception(graph, t);
5140                                 } catch (Throwable t2) {
5141                                         Logger.defaultLogError(t2);
5142                                 }
5143 //                              impl.state.barrier.dec();
5144                         }
5145
5146                         @Override
5147                         public void execute(ReadGraphImpl graph, int i) {
5148                                 try {
5149                                         procedure.execute(graph, querySupport.getResource(i));
5150                                 } catch (Throwable t2) {
5151                                         Logger.defaultLogError(t2);
5152                                 }
5153                         }
5154
5155                         @Override
5156                         public void finished(ReadGraphImpl graph) {
5157                                 try {
5158                                         procedure.finished(graph);
5159                                 } catch (Throwable t2) {
5160                                         Logger.defaultLogError(t2);
5161                                 }
5162 //                              impl.state.barrier.dec();
5163                         }
5164
5165                 });
5166
5167         }
5168
5169         @Override
5170         final public <T> void query(final ReadGraphImpl impl, final AsyncRead<T> request, final CacheEntry parent, final AsyncProcedure<T> procedure, ListenerBase listener) {
5171
5172                 assert(request != null);
5173                 assert(procedure != null);
5174
5175 //              if(AsyncBarrierImpl.BOOKKEEPING) impl.state.barrier.inc(request, "#" + request.toString() + ".1999");
5176 //              else impl.state.barrier.inc(null, null);
5177
5178                 runAsyncRead(impl, request, parent, listener, procedure);
5179
5180         }
5181
5182         @Override
5183         final public <T> T tryQuery(final ReadGraphImpl graph, final Read<T> request) throws DatabaseException {
5184
5185                 assert(graph != null);
5186                 assert(request != null);
5187
5188                 final ReadEntry entry = readMap.get(request);
5189                 if(entry != null && entry.isReady()) {
5190                     return (T)entry.get(graph, this, null);
5191                 } else {
5192                         return request.perform(graph);
5193                 }
5194
5195         }
5196
5197     final public <T> T tryQuery(final ReadGraphImpl graph, final ExternalRead<T> request) throws DatabaseException {
5198
5199         assert(graph != null);
5200         assert(request != null);
5201
5202         final ExternalReadEntry<T> entry = externalReadMap.get(request);
5203         if(entry != null && entry.isReady()) {
5204             if(entry.isExcepted()) {
5205                 Throwable t = (Throwable)entry.getResult();
5206                 if(t instanceof DatabaseException) throw (DatabaseException)t;
5207                 else throw new DatabaseException(t);
5208             } else {
5209                 return (T)entry.getResult();
5210             }            
5211         } else {
5212
5213             final DataContainer<T> result = new DataContainer<T>();
5214             final DataContainer<Throwable> exception = new DataContainer<Throwable>();
5215             
5216             request.register(graph, new Listener<T>() {
5217                 
5218                 @Override
5219                 public void exception(Throwable t) {
5220                     exception.set(t);
5221                 }
5222
5223                 @Override
5224                 public void execute(T t) {
5225                     result.set(t);
5226                 }
5227
5228                 @Override
5229                 public boolean isDisposed() {
5230                     return true;
5231                 }
5232             
5233             });
5234             
5235             Throwable t = exception.get();
5236             if(t != null) {
5237                 if(t instanceof DatabaseException) throw (DatabaseException)t;
5238                 else throw new DatabaseException(t);
5239             }
5240             
5241             return result.get();
5242
5243         }
5244
5245     }
5246         
5247         @Override
5248         final public <T> void tryQuery(final ReadGraphImpl graph, final AsyncRead<T> request, AsyncProcedure<T> procedure) {
5249
5250                 assert(graph != null);
5251                 assert(request != null);
5252
5253                 final AsyncReadEntry entry = asyncReadMap.get(request);
5254                 if(entry != null && entry.isReady()) {
5255                         if(entry.isExcepted()) {
5256                                 procedure.exception(graph, (Throwable)entry.getResult());
5257                         } else {
5258                                 procedure.execute(graph, (T)entry.getResult());
5259                         }
5260                 } else {
5261                         request.perform(graph, procedure);
5262                 }
5263
5264         }
5265
5266         @Override
5267         final public <T> void query(final ReadGraphImpl impl, final MultiRead<T> request, final CacheEntry parent, final AsyncMultiProcedure<T> procedure, ListenerBase listener) {
5268
5269                 assert(request != null);
5270                 assert(procedure != null);
5271
5272 //              impl.state.barrier.inc(null, null);
5273
5274                 queryMultiRead(impl, request, parent, listener, procedure);
5275
5276         }
5277
5278         @Override
5279         final public <T> void query(final ReadGraphImpl impl, final AsyncMultiRead<T> request, final CacheEntry parent, final AsyncMultiProcedure<T> procedure, ListenerBase listener) {
5280
5281                 assert(request != null);
5282                 assert(procedure != null);
5283
5284 //              impl.state.barrier.inc();
5285
5286                 runAsyncMultiRead(impl, request, parent, listener, new AsyncMultiProcedure<T>() {
5287
5288                         public void execute(AsyncReadGraph graph, T result) {
5289
5290                                 try {
5291                                         procedure.execute(graph, result);
5292                                 } catch (Throwable t2) {
5293                                         Logger.defaultLogError(t2);
5294                                 }
5295                         }
5296
5297                         @Override
5298                         public void finished(AsyncReadGraph graph) {
5299
5300                                 try {
5301                                         procedure.finished(graph);
5302                                 } catch (Throwable t2) {
5303                                         Logger.defaultLogError(t2);
5304                                 }
5305
5306 //                              impl.state.barrier.dec();
5307
5308                         }
5309
5310                         @Override
5311                         public String toString() {
5312                                 return procedure.toString();
5313                         }
5314
5315                         @Override
5316                         public void exception(AsyncReadGraph graph, Throwable t) {
5317
5318                                 try {
5319                                         procedure.exception(graph, t);
5320                                 } catch (Throwable t2) {
5321                                         Logger.defaultLogError(t2);
5322                                 }
5323
5324 //                              impl.state.barrier.dec();
5325
5326                         }
5327
5328                 });
5329
5330         }
5331
5332         @Override
5333         final public <T> void query(final ReadGraphImpl impl, final ExternalRead<T> request, final CacheEntry parent, final Procedure<T> procedure, ListenerBase listener) {
5334
5335                 assert(request != null);
5336                 assert(procedure != null);
5337
5338                 queryPrimitiveRead(impl, request, parent, listener, new Procedure<T>() {
5339
5340                         @Override
5341                         public void execute(T result) {
5342                                 try {
5343                                         procedure.execute(result);
5344                                 } catch (Throwable t2) {
5345                                         Logger.defaultLogError(t2);
5346                                 }
5347                         }
5348
5349                         @Override
5350                         public String toString() {
5351                                 return procedure.toString();
5352                         }
5353
5354                         @Override
5355                         public void exception(Throwable t) {
5356                                 try {
5357                                         procedure.exception(t);
5358                                 } catch (Throwable t2) {
5359                                         Logger.defaultLogError(t2);
5360                                 }
5361                         }
5362
5363                 });
5364
5365         }
5366
5367         @Override
5368         public VirtualGraph getProvider(Resource subject, Resource predicate, Resource object) {
5369                 
5370                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
5371                 
5372         }
5373         
5374         @Override
5375         public VirtualGraph getProvider(Resource subject, Resource predicate) {
5376                 
5377                 return querySupport.getProvider(querySupport.getId(subject), querySupport.getId(predicate));
5378                 
5379         }
5380
5381         @Override
5382         public VirtualGraph getValueProvider(Resource subject) {
5383                 
5384                 return querySupport.getValueProvider(querySupport.getId(subject));
5385                 
5386         }
5387
5388         public boolean resumeTasks(ReadGraphImpl graph) {
5389
5390                 return querySupport.resume(graph);
5391
5392         }
5393         
5394         public boolean isImmutable(int resourceId) {
5395                 return querySupport.isImmutable(resourceId);
5396         }
5397
5398         public boolean isImmutable(Resource resource) {
5399                 ResourceImpl impl = (ResourceImpl)resource;
5400                 return isImmutable(impl.id);
5401         }
5402         
5403         private Layer0 L0;
5404         
5405         public Layer0 getL0(ReadGraph graph) {
5406                 if(L0 == null) {
5407                         L0 = Layer0.getInstance(graph);
5408                 }
5409                 return L0;
5410         }
5411         
5412 }