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