]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java
Multiple reader thread support for db client
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / QueryCacheBase.java
diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java
new file mode 100644 (file)
index 0000000..b3d1c5f
--- /dev/null
@@ -0,0 +1,1215 @@
+package org.simantics.db.impl.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.ObjectResourceIdMap;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RelationInfo;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.impl.DebugPolicy;
+import org.simantics.db.impl.graph.ReadGraphImpl;
+import org.simantics.db.impl.procedure.InternalProcedure;
+import org.simantics.db.impl.query.QueryProcessor.SessionTask;
+import org.simantics.db.procedure.AsyncMultiProcedure;
+import org.simantics.db.procedure.AsyncProcedure;
+import org.simantics.db.procedure.Listener;
+import org.simantics.db.procedure.ListenerBase;
+import org.simantics.db.procedure.Procedure;
+import org.simantics.db.procedure.SyncMultiProcedure;
+import org.simantics.db.request.AsyncMultiRead;
+import org.simantics.db.request.AsyncRead;
+import org.simantics.db.request.ExternalRead;
+import org.simantics.db.request.MultiRead;
+import org.simantics.db.request.Read;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+
+public class QueryCacheBase {
+
+       // Statistics
+       final int THREADS;
+       public final int THREAD_MASK;
+       int                                             hits                  = 0;
+       int                                             misses                = 0;
+       int                                             updates               = 0;
+       public int                                              size                  = 0;
+
+       public volatile boolean dirty = false;
+       public boolean collecting = false;
+
+       protected final THashMap<String, URIToResource>                           uRIToResourceMap;
+       //protected final THashMap<String, NamespaceIndex>                          namespaceIndexMap;
+       protected final UnaryQueryHashMap<InternalProcedure<ObjectResourceIdMap<String>>> childMapMap;
+       protected final DoubleKeyQueryHashMap<IntProcedure>                       objectsMap;
+       protected final DoubleKeyQueryHashMap<TripleIntProcedure>                 assertedStatementsMap;
+       protected final DoubleKeyQueryHashMap<IntProcedure>                       directObjectsMap;
+       protected final DoubleKeyQueryHashMap<TripleIntProcedure>                 statementsMap;
+       protected final UnaryQueryHashMap<InternalProcedure<IntSet>>              typesMap;
+       protected final UnaryQueryHashMap<IntProcedure>                           principalTypesMap;
+       protected final UnaryQueryHashMap<InternalProcedure<IntSet>>              predicatesMap;
+       protected final UnaryQueryHashMap<InternalProcedure<IntSet>>              superTypesMap;
+       protected final UnaryQueryHashMap<InternalProcedure<IntSet>>              typeHierarchyMap;
+       protected final UnaryQueryHashMap<InternalProcedure<IntSet>>              superRelationsMap;
+
+       protected final UnaryQueryHashMap<IntProcedure>                           orderedSetMap;
+       protected final UnaryQueryHashMap<IntProcedure>                           assertedPredicatesMap;
+       protected final UnaryQueryHashMap<InternalProcedure<IntSet>>              directPredicatesMap;
+       protected final UnaryQueryHashMap<IntProcedure>                           directSuperRelationsMap;
+
+       protected final UnaryQueryHashMap<InternalProcedure<RelationInfo>>        relationInfoQueryMap;
+       protected final UnaryQueryHashMap<InternalProcedure<byte[]>>              valueQueryMap;
+
+       protected final StableHashMap<AsyncRead, AsyncReadEntry>                  asyncReadEntryMap; 
+       protected final StableHashMap<Read, ReadEntry>                            readEntryMap;
+       protected final StableHashMap<MultiRead, MultiReadEntry>                  multiReadEntryMap; 
+       protected final StableHashMap<AsyncMultiRead, AsyncMultiReadEntry>        asyncMultiReadEntryMap; 
+       protected final StableHashMap<ExternalRead, ExternalReadEntry>            externalReadEntryMap; 
+
+       final THashMap<CacheEntry, ArrayList<ListenerEntry>>                      listeners;
+
+       public final QuerySupport                                                 querySupport;
+
+       public QueryCacheBase(QuerySupport querySupport, int threads) {
+
+               THREADS = threads;
+               THREAD_MASK = threads - 1;
+
+               this.querySupport = querySupport;
+               directPredicatesMap = new UnaryQueryHashMap();
+               directSuperRelationsMap = new UnaryQueryHashMap();
+               valueQueryMap = new UnaryQueryHashMap();
+               principalTypesMap = new UnaryQueryHashMap();
+               uRIToResourceMap = new THashMap<String, URIToResource>();
+               //namespaceIndexMap = new THashMap<String, NamespaceIndex>();
+               childMapMap = new UnaryQueryHashMap<InternalProcedure<ObjectResourceIdMap<String>>>();
+               relationInfoQueryMap = new UnaryQueryHashMap();
+               typeHierarchyMap = new UnaryQueryHashMap();
+               superTypesMap = new UnaryQueryHashMap();
+               superRelationsMap = new UnaryQueryHashMap();
+               typesMap = new UnaryQueryHashMap();
+               objectsMap = new DoubleKeyQueryHashMap();
+               orderedSetMap = new UnaryQueryHashMap();
+               predicatesMap = new UnaryQueryHashMap();
+               statementsMap = new DoubleKeyQueryHashMap();
+               directObjectsMap = new DoubleKeyQueryHashMap();
+               assertedPredicatesMap = new UnaryQueryHashMap();
+               assertedStatementsMap = new DoubleKeyQueryHashMap();
+               asyncReadEntryMap = new StableHashMap<AsyncRead, AsyncReadEntry>(); 
+               readEntryMap = new StableHashMap<Read, ReadEntry>();
+               asyncMultiReadEntryMap = new StableHashMap<AsyncMultiRead, AsyncMultiReadEntry>(); 
+               multiReadEntryMap = new StableHashMap<MultiRead, MultiReadEntry>(); 
+               externalReadEntryMap = new StableHashMap<ExternalRead, ExternalReadEntry>(); 
+               listeners = new THashMap<CacheEntry, ArrayList<ListenerEntry>>(10, 0.75f);
+       }
+
+//     public <T> Object performQuery(ReadGraphImpl parentGraph, final AsyncRead<T> query, final CacheEntryBase entry_, AsyncProcedure procedure_) throws DatabaseException {
+//
+//             AsyncReadEntry<T> entry = (AsyncReadEntry<T>)entry_;
+//             AsyncProcedure<T> procedure = (AsyncProcedure<T>)procedure_;
+//
+//             ReadGraphImpl queryGraph = parentGraph.withParent(entry_);
+//
+//             try {
+//                     
+//                     query.perform(queryGraph, new AsyncProcedure<T>() {
+//
+//                             @Override
+//                             public void execute(AsyncReadGraph returnGraph, T result) {
+//                                     ReadGraphImpl impl = (ReadGraphImpl)returnGraph;
+//                                     entry.addOrSet(parentGraph, result);
+//                                     try {
+//                                             procedure.execute(parentGraph, result);
+//                                     } catch (Throwable t) {
+//                                             t.printStackTrace();
+//                                     }
+////                                   parentBarrier.dec(query);
+//                             }
+//
+//                             @Override
+//                             public void exception(AsyncReadGraph returnGraph, Throwable t) {
+//                                     ReadGraphImpl impl = (ReadGraphImpl)returnGraph;
+////                                   AsyncReadGraph resumeGraph = finalParentGraph.newAsync();
+//                                     entry.except(parentGraph, t);
+//                                     try {
+//                                             procedure.exception(parentGraph, t);
+//                                     } catch (Throwable t2) {
+//                                             t2.printStackTrace();
+//                                     }
+////                                   parentBarrier.dec(query);
+//                             }
+//
+//                             @Override
+//                             public String toString() {
+//                                     return procedure.toString();
+//                             }
+//
+//                     });
+//
+//             } catch (Throwable t) {
+//
+//                     entry.except(t);
+//                     try {
+//                             procedure.exception(parentGraph, t);
+//                     } catch (Throwable t2) {
+//                             t2.printStackTrace();
+//                     }
+////                   parentBarrier.dec(query);
+//
+//             }
+//             
+//             return null;
+//             
+//     }
+
+//     public <T> Object performQuery(ReadGraphImpl parentGraph, final Read<T> query, final CacheEntryBase entry_, AsyncProcedure procedure_) throws DatabaseException {
+//
+//             ReadGraphImpl queryGraph = parentGraph.withParent(entry_);
+//
+//             ReadEntry entry = (ReadEntry)entry_;
+//
+//             try {
+//
+//                     T result = (T)query.perform(queryGraph);
+//                     entry.addOrSet(queryGraph, result);
+//
+//                     return (T)entry.get(parentGraph, procedure_);
+//
+//             }  catch (Throwable t) {
+//
+//                     entry.except(t);
+//                     return (T)entry.get(parentGraph, procedure_);
+//
+//             }
+//             
+//     }
+
+       public <T> Object performQuery(ReadGraphImpl parentGraph, final ExternalRead<T> query, final CacheEntryBase entry_, AsyncProcedure procedure_) throws DatabaseException {
+
+               ExternalReadEntry entry = (ExternalReadEntry)entry_;
+               AsyncProcedure<T> procedure = (AsyncProcedure<T>)procedure_;
+               
+               try {
+
+                       query.register(parentGraph, new Listener<T>() {
+
+                               AtomicBoolean used = new AtomicBoolean(false);
+
+                               @Override
+                               public void execute(T result) {
+
+                                       // Just for safety
+                                       if(entry.isDiscarded()) return;
+
+                                       if(used.compareAndSet(false, true)) {
+                                               //entry.setPending();
+                                               entry.addOrSet(parentGraph.processor, result);
+                                               procedure.execute(parentGraph, result);
+                                       } else {
+                                               entry.queue(result);
+                                               parentGraph.processor.updatePrimitive(query);
+                                       }
+
+                               }
+
+                               @Override
+                               public void exception(Throwable t) {
+
+                                       entry.except(t);
+
+                                       if(used.compareAndSet(false, true)) {
+                                               procedure.exception(parentGraph, t);
+                                       } else {
+//                                             entry.queue(result);
+                                               parentGraph.processor.updatePrimitive(query);
+                                       }
+
+                               }
+
+                               @Override
+                               public String toString() {
+                                       return procedure.toString();
+                               }
+
+                               @Override
+                               public boolean isDisposed() {
+                                       return entry.isDiscarded() || !parentGraph.processor.isBound(entry);
+                               }
+
+                       });
+
+                       return entry.getResult();
+
+               } catch (Throwable t) {
+
+                       entry.except(t);
+                       procedure.exception(parentGraph, t);
+                       return entry.getResult();
+
+               }
+
+       }
+
+       public <T> Object performQuery(ReadGraphImpl parentGraph, final AsyncMultiRead<T> query, final CacheEntryBase entry_, Object procedure_) throws DatabaseException {
+
+               ReadGraphImpl queryGraph = parentGraph.withParent(entry_);
+
+               AsyncMultiReadEntry entry = (AsyncMultiReadEntry)entry_;
+               AsyncMultiProcedure<T> procedure = (AsyncMultiProcedure<T>)procedure_;
+
+               try {
+
+                       query.perform(queryGraph, new AsyncMultiProcedure<T>() {
+
+                               @Override
+                               public void execute(AsyncReadGraph graph, T result) {
+                                       ReadGraphImpl impl = (ReadGraphImpl)graph;
+                                       entry.addOrSet(result);
+                                       try {
+                                               procedure.execute(parentGraph, result);
+                                       } catch (Throwable t) {
+                                               t.printStackTrace();
+                                       }
+                               }
+
+                               @Override
+                               public void finished(AsyncReadGraph graph) {
+                                       ReadGraphImpl impl = (ReadGraphImpl)graph;
+                                       entry.finish(parentGraph);
+                                       try {
+                                               procedure.finished(parentGraph);
+                                       } catch (Throwable t) {
+                                               t.printStackTrace();
+                                       }
+                               }
+
+                               @Override
+                               public void exception(AsyncReadGraph graph, Throwable t) {
+                                       ReadGraphImpl impl = (ReadGraphImpl)graph;
+                                       entry.except(parentGraph, t);
+                                       try {
+                                               procedure.exception(parentGraph, t);
+                                       } catch (Throwable t2) {
+                                               t2.printStackTrace();
+                                       }
+                               }
+
+                       });
+
+                       return entry.getResult();
+
+               } catch (Throwable t) {
+
+                       entry.except(t);
+                       try {
+                               procedure.exception(parentGraph, t);
+                       } catch (Throwable t2) {
+                               t2.printStackTrace();
+                       }
+
+                       return entry.getResult();
+
+               }
+
+       }
+
+       public <T> Object performQuery(ReadGraphImpl parentGraph, final MultiRead<T> query, final CacheEntryBase entry_, Object procedure_) throws DatabaseException {
+
+               ReadGraphImpl queryGraph = parentGraph.withParent(entry_);
+
+               MultiReadEntry entry = (MultiReadEntry)entry_;
+               SyncMultiProcedure<T> procedure = (SyncMultiProcedure<T>)procedure_;
+
+               try {
+
+                       query.perform(queryGraph, new SyncMultiProcedure<T>() {
+
+                               @Override
+                               public void execute(ReadGraph graph, T result) {
+                                       ReadGraphImpl impl = (ReadGraphImpl)graph;
+                                       entry.addOrSet(result);
+                                       try {
+                                               procedure.execute(parentGraph, result);
+                                       } catch (Throwable t) {
+                                               t.printStackTrace();
+                                       }
+                               }
+
+                               @Override
+                               public void finished(ReadGraph graph) {
+                                       ReadGraphImpl impl = (ReadGraphImpl)graph;
+                                       entry.finish(parentGraph);
+                                       try {
+                                               procedure.finished(parentGraph);
+                                       } catch (Throwable t) {
+                                               t.printStackTrace();
+                                       }
+                               }
+
+                               @Override
+                               public void exception(ReadGraph graph, Throwable t) {
+                                       ReadGraphImpl impl = (ReadGraphImpl)graph;
+                                       entry.except((DatabaseException)t);
+                                       try {
+                                               procedure.exception(parentGraph, t);
+                                       } catch (Throwable t2) {
+                                               t2.printStackTrace();
+                                       }
+                               }
+
+                       });
+
+                       return entry.getResult();
+
+               } catch (Throwable t) {
+
+                       entry.except(t);
+                       try {
+                               procedure.exception(parentGraph, t);
+                       } catch (Throwable t2) {
+                               t2.printStackTrace();
+                       }
+
+                       return entry.getResult();
+
+               }
+               
+       }
+       
+       public ListenerEntry registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) {
+
+               if (parent != null && !inferred) {
+                       try {
+                               if(!child.isImmutable(graph)) {
+                                       synchronized(child) {
+                                               child.addParent(parent);
+                                       }
+                               }
+                       } catch (DatabaseException e) {
+                               Logger.defaultLogError(e);
+                       }
+                       if(DebugPolicy.DEPENDENCIES) System.out.println(child + " -> " + parent);
+               }
+
+               if (listener != null) {
+                       return registerListener(child, listener, procedure);
+               } else {
+                       return null;
+               }
+
+       }
+       
+       public synchronized ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) {
+
+               assert (entry != null);
+
+               if (base.isDisposed())
+                       return null;
+
+               return addListener(entry, base, procedure);
+
+       }
+
+       protected void primeListenerEntry(final ListenerEntry entry, final Object result) {
+               entry.setLastKnown(result);
+       }
+
+       private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) {
+
+               assert (entry != null);
+               assert (procedure != null);
+
+               ArrayList<ListenerEntry> list = listeners.get(entry);
+               if (list == null) {
+                       list = new ArrayList<ListenerEntry>(1);
+                       listeners.put(entry, list);
+               }
+
+               ListenerEntry result = new ListenerEntry(entry, base, procedure);
+               int currentIndex = list.indexOf(result);
+               // There was already a listener
+               if(currentIndex > -1) {
+                       ListenerEntry current = list.get(currentIndex);
+                       if(!current.base.isDisposed()) return null;
+                       list.set(currentIndex, result);
+               } else {
+                       list.add(result);
+               }
+
+               if(DebugPolicy.LISTENER) {
+                       new Exception().printStackTrace();
+                       System.out.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure);
+               }
+
+               return result;
+
+       }
+       
+       
+       public Collection<CacheEntry> getRootList() {
+
+               ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
+
+               for (Object e : valueQueryMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : directPredicatesMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : directSuperRelationsMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : objectsMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : directObjectsMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : principalTypesMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : superRelationsMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : superTypesMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : typesMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : objectsMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : assertedStatementsMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : readEntryMap.values()) {
+                       if(e instanceof CacheEntry) {
+                               result.add((CacheEntry) e);
+                       } else {
+                               System.err.println("e=" + e);
+                       }
+               }
+               for (Object e : asyncReadEntryMap.values()) {
+                       if(e instanceof CacheEntry) {
+                               result.add((CacheEntry) e);
+                       } else {
+                               System.err.println("e=" + e);
+                       }
+               }
+               for (Object e : externalReadEntryMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+               for (Object e : orderedSetMap.values()) {
+                       result.add((CacheEntry) e);
+               }
+
+               return result;
+
+       }
+
+       public int calculateCurrentSize() {
+
+               int realSize = 0;
+
+               realSize += directPredicatesMap.size();
+               realSize += directSuperRelationsMap.size();
+               realSize += principalTypesMap.size();
+               realSize += uRIToResourceMap.size();
+               //realSize += namespaceIndexMap.size();
+               realSize += childMapMap.size();
+
+               realSize += relationInfoQueryMap.size();
+               realSize += superTypesMap.size();
+               realSize += typeHierarchyMap.size();
+               realSize += superRelationsMap.size();
+               realSize += typesMap.size();
+
+               realSize += valueQueryMap.size();
+               realSize += directObjectsMap.size();
+               realSize += objectsMap.size();
+               realSize += orderedSetMap.size();
+               realSize += predicatesMap.size();
+
+               realSize += statementsMap.size();
+               realSize += assertedPredicatesMap.size();
+               realSize += assertedStatementsMap.size();
+               realSize += externalReadEntryMap.size();
+               realSize += asyncReadEntryMap.size();
+
+               realSize += readEntryMap.size();
+               realSize += asyncMultiReadEntryMap.size();
+               realSize += multiReadEntryMap.size();
+
+               return realSize;
+
+       }
+
+       CacheCollectionResult allCaches(CacheCollectionResult result) {
+
+               int level = Integer.MAX_VALUE;
+               directPredicatesMap.values(level, result);
+               directSuperRelationsMap.values(level, result);
+               principalTypesMap.values(level, result);
+               for(CacheEntryBase e : uRIToResourceMap.values())
+                       if(e.getLevel() <= level)
+                               result.add(e);
+//             for(CacheEntryBase e : namespaceIndexMap.values())
+//                     if(e.getLevel() <= level)
+//                             result.add(e);
+
+               childMapMap.values(level, result);
+
+               relationInfoQueryMap.values(level, result);
+               superTypesMap.values(level, result);
+               typeHierarchyMap.values(level, result);
+               superRelationsMap.values(level, result);
+               typesMap.values(level, result);
+
+               valueQueryMap.values(level, result);
+               directObjectsMap.values(level, result);
+               objectsMap.values(level, result);
+               orderedSetMap.values(level, result);
+               predicatesMap.values(level, result);
+
+               statementsMap.values(level, result);
+               assertedPredicatesMap.values(level, result);
+               assertedStatementsMap.values(level, result);
+               externalReadEntryMap.values(level, result);
+               asyncReadEntryMap.values(level, result);
+
+               readEntryMap.values(level, result);
+               asyncMultiReadEntryMap.values(level, result);
+               multiReadEntryMap.values(level, result);
+
+               return result;
+
+       }
+
+       public void scanPending() {
+
+               ArrayList<CacheEntry> entries = new ArrayList<CacheEntry>();
+
+               entries.addAll(directPredicatesMap.values());
+               entries.addAll(directSuperRelationsMap.values());
+               entries.addAll(principalTypesMap.values());
+               entries.addAll(uRIToResourceMap.values());
+               //entries.addAll(namespaceIndexMap.values());
+               entries.addAll(childMapMap.values());
+               entries.addAll(relationInfoQueryMap.values());
+               entries.addAll(superTypesMap.values());
+               entries.addAll(superRelationsMap.values());
+               entries.addAll(typesMap.values());
+               entries.addAll(valueQueryMap.values());
+               entries.addAll(directObjectsMap.values());
+               entries.addAll(objectsMap.values());
+               entries.addAll(orderedSetMap.values());
+               entries.addAll(predicatesMap.values());
+               entries.addAll(orderedSetMap.values());
+               entries.addAll(statementsMap.values());
+               //                      entries.addAll(assertedObjectsMap.values());
+               entries.addAll(assertedPredicatesMap.values());
+               entries.addAll(assertedStatementsMap.values());
+               entries.addAll(externalReadEntryMap.values());
+               entries.addAll(asyncReadEntryMap.values());
+               entries.addAll(externalReadEntryMap.values());
+               entries.addAll(readEntryMap.values());
+               entries.addAll(asyncMultiReadEntryMap.values());
+               entries.addAll(multiReadEntryMap.values());
+               entries.addAll(readEntryMap.values());
+               System.out.println(entries.size() + " entries.");
+               for(Object e : entries) {
+                       if(e instanceof CacheEntry) {
+                               CacheEntry en = (CacheEntry)e;
+                               if(en.isPending()) System.out.println("pending " + e);
+                               if(en.isExcepted()) System.out.println("excepted " + e);
+                               if(en.isDiscarded()) System.out.println("discarded " + e);
+                               if(en.isRefuted()) System.out.println("refuted " + e);
+                               if(en.isFresh()) System.out.println("fresh " + e);
+                       } else {
+                               //System.out.println("Unknown object " + e);
+                       }
+               }
+       }
+
+       public static void waitPending(QueryProcessor processor, CacheEntry entry) throws DatabaseException {
+
+               int counter = 0;
+               while(entry.isPending()) {
+                       try {
+                               SessionTask task = null;//processor.getOwnTask(processor.thread.get());
+                               if(task != null) {
+                                       task.run(processor.thread.get());
+                               } else {
+                                       Thread.sleep(1);
+                                       counter++;
+                                       if(counter > 5000) {
+                                               CacheEntryBase base = ((CacheEntryBase)entry);
+//                                             if(base.created != null) {
+//                                                     System.err.println("created:");
+//                                                     base.created.printStackTrace();
+//                                             }
+//                                             if(base.performed != null) {
+//                                                     System.err.println("performed:");
+//                                                     base.performed.printStackTrace();
+//                                             }
+//                                             if(base.ready != null) {
+//                                                     System.err.println("ready:");
+//                                                     base.ready.printStackTrace();
+//                                             }
+                                               new Exception("Timeout waiting for request to complete: " + entry.getOriginalRequest().toString()).printStackTrace();
+                                               throw new DatabaseException("Timeout waiting for request to complete.");
+                                               //System.err.println("asd");
+                                               //base.getQuery().recompute(null, null, entry);
+                                       }
+                               }
+                       } catch (InterruptedException e) {
+                       }
+               }
+
+       }
+
+       //////////////////////////////////////
+
+       public static Collection<Objects> entriesObjects(QueryProcessor processor, int r1) {
+               synchronized(processor.cache.objectsMap) {
+                       return processor.cache.objectsMap.values(r1);
+               }
+       }
+
+       public static Collection<Objects> entriesObjects(QueryProcessor processor) {
+               synchronized(processor.cache.objectsMap) {
+                       return processor.cache.objectsMap.values();
+               }
+       }
+
+       public static Collection<CacheEntry> entriesDirectPredicates(QueryProcessor processor) {
+               synchronized(processor.cache.directPredicatesMap) {
+                       return processor.cache.directPredicatesMap.values();
+               }
+       }
+
+       static final Collection<DirectObjects> entriesDirectObjects(final QueryProcessor processor, final int r1) {
+               DoubleKeyQueryHashMap<IntProcedure> hash = processor.cache.directObjectsMap;
+               return hash.values(r1);
+       }
+
+       static final Collection<Statements> entriesStatements(final QueryProcessor processor, final int r1) {
+               return processor.cache.statementsMap.values(r1);
+       }
+
+       static final Types entryTypes(final QueryProcessor processor, final int r) {
+               return (Types)processor.cache.typesMap.get(r);
+       }
+
+       static final PrincipalTypes entryPrincipalTypes(final QueryProcessor processor, final int r) {
+               return (PrincipalTypes)processor.cache.principalTypesMap.get(r);
+       }
+
+       static final OrderedSet entryOrderedSet(final QueryProcessor processor, final int r) {
+               return (OrderedSet)processor.cache.orderedSetMap.get(r);
+       }
+
+       static final ValueQuery entryValueQuery(final QueryProcessor processor, final int r) {
+               return (ValueQuery)processor.cache.valueQueryMap.get(r);
+       }
+
+       static final DirectPredicates entryDirectPredicates(final QueryProcessor processor, final int r) {
+               return (DirectPredicates)processor.cache.directPredicatesMap.get(r);
+       }
+
+       public static final ReadEntry entryRead(final QueryProcessor processor, final Read request) {
+               return (ReadEntry)processor.cache.readEntryMap.get(request);
+       }
+
+       public static final MultiReadEntry entryMultiRead(final QueryProcessor processor, final MultiRead request) {
+               return (MultiReadEntry)processor.cache.multiReadEntryMap.get(request);
+       }
+
+       public static final AsyncReadEntry entryAsyncRead(final QueryProcessor processor, final AsyncRead request) {
+               return (AsyncReadEntry)processor.cache.asyncReadEntryMap.get(request);
+       }
+
+       public static final AsyncMultiReadEntry entryAsyncMultiRead(final QueryProcessor processor, final AsyncMultiRead request) {
+               return (AsyncMultiReadEntry)processor.cache.asyncMultiReadEntryMap.get(request);
+       }
+
+       protected static final long keyR2(long r1, long r2) {
+               long result = (r1<<32) | (r2 & 0xffffffffL); 
+               return result;
+       }
+
+       protected static final <T> T id(T o) {
+               return o;
+       }
+
+       protected static final int keyR(int r) {
+               return r;
+       }
+
+       protected static final String keyID(String id) {
+               return id;
+       }
+
+       protected static InternalProcedure<IntSet> emptyIntSetProcedure = new InternalProcedure<IntSet>() {
+
+               @Override
+               public void execute(ReadGraphImpl graph, IntSet result) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+
+       }; 
+
+       protected static InternalProcedure<byte[]> emptyBytesProcedure = new InternalProcedure<byte[]>() {
+
+               @Override
+               public void execute(ReadGraphImpl graph, byte[] bytes) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+
+       }; 
+
+       protected static InternalProcedure<Integer> emptyIntegerProcedure = new InternalProcedure<Integer>() {
+
+               @Override
+               public void execute(ReadGraphImpl graph, Integer i) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+
+       }; 
+
+
+       protected static InternalProcedure<TObjectIntHashMap<String>> emptyNamespaceProcedure = new InternalProcedure<TObjectIntHashMap<String>>() {
+
+               @Override
+               public void execute(ReadGraphImpl graph, TObjectIntHashMap<String> i) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+
+       }; 
+
+
+       protected static InternalProcedure<RelationInfo> emptyRelationInfoProcedure = new InternalProcedure<RelationInfo>() {
+
+               @Override
+               public void execute(ReadGraphImpl graph, RelationInfo i) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+
+       };
+
+       protected static InternalProcedure<ObjectResourceIdMap<String>> emptyChildMapProcedure = new InternalProcedure<ObjectResourceIdMap<String>>() {
+
+               @Override
+               public void execute(ReadGraphImpl graph, ObjectResourceIdMap<String> i) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+
+       };
+
+       protected static IntProcedure emptyIntProcedure = new IntProcedure() {
+
+               @Override
+               public void finished(ReadGraphImpl graph) {
+               }
+
+               @Override
+               public void execute(ReadGraphImpl graph, int i) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+       };
+
+       protected static TripleIntProcedure emptyTripleIntProcedure = new TripleIntProcedure() {
+
+               @Override
+               public void execute(ReadGraphImpl graph, int s, int p, int o) {
+               }
+
+               @Override
+               public void finished(ReadGraphImpl graph) {
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) {
+               }
+
+       }; 
+
+       protected static AsyncProcedure<Object> emptyAsyncProcedure = new AsyncProcedure<Object>() {
+
+               @Override
+               public void execute(AsyncReadGraph graph, Object result) {
+               }
+
+               @Override
+               public void exception(AsyncReadGraph graph, Throwable throwable) {
+               }
+
+       };
+
+       protected static AsyncMultiProcedure<Object> emptyAsyncMultiProcedure = new AsyncMultiProcedure<Object>() {
+
+               @Override
+               public void execute(AsyncReadGraph graph, Object result) {
+               }
+
+               @Override
+               public void finished(AsyncReadGraph graph) {
+               }
+
+               @Override
+               public void exception(AsyncReadGraph graph, Throwable throwable) {
+               }
+
+       }; 
+
+       protected static SyncMultiProcedure<Object> emptySyncMultiProcedure = new SyncMultiProcedure<Object>() {
+
+               @Override
+               public void execute(ReadGraph graph, Object result) {
+               }
+
+               @Override
+               public void finished(ReadGraph graph) {
+               }
+
+               @Override
+               public void exception(ReadGraph graph, Throwable throwable) {
+               }
+
+       };
+
+       protected static InternalProcedure<IntSet> emptyProcedureTypes = emptyIntSetProcedure;
+       protected static InternalProcedure<IntSet> emptyProcedureSuperTypes = emptyIntSetProcedure;
+       protected static InternalProcedure<IntSet> emptyProcedureTypeHierarchy = emptyIntSetProcedure;
+       protected static InternalProcedure<IntSet> emptyProcedureSuperRelations = emptyIntSetProcedure;
+       protected static InternalProcedure<IntSet> emptyProcedurePredicates = emptyIntSetProcedure;
+       protected static InternalProcedure<IntSet> emptyProcedureDirectPredicates = emptyIntSetProcedure;
+
+       protected static IntProcedure emptyProcedureObjects = emptyIntProcedure;
+       protected static IntProcedure emptyProcedureDirectObjects = emptyIntProcedure;
+       protected static IntProcedure emptyProcedurePrincipalTypes = emptyIntProcedure;
+       protected static IntProcedure emptyProcedureDirectSuperRelations = emptyIntProcedure;
+       protected static IntProcedure emptyProcedureAssertedPredicates = emptyIntProcedure;
+       protected static IntProcedure emptyProcedureOrderedSet = emptyIntProcedure;
+
+       protected static TripleIntProcedure emptyProcedureStatements = emptyTripleIntProcedure;
+       protected static TripleIntProcedure emptyProcedureAssertedStatements = emptyTripleIntProcedure;
+
+       protected static InternalProcedure<byte[]> emptyProcedureValueQuery = emptyBytesProcedure;
+
+       protected static InternalProcedure<Integer> emptyProcedureURIToResource = emptyIntegerProcedure;
+       protected static InternalProcedure<TObjectIntHashMap<String>> emptyProcedureNamespaceIndex = emptyNamespaceProcedure;
+       protected static InternalProcedure<ObjectResourceIdMap<String>> emptyProcedureChildMap = emptyChildMapProcedure;
+       protected static InternalProcedure<RelationInfo> emptyProcedureRelationInfoQuery = emptyRelationInfoProcedure;
+
+       protected static AsyncProcedure emptyProcedureReadEntry = emptyAsyncProcedure;
+       protected static AsyncProcedure emptyProcedureAsyncReadEntry = emptyAsyncProcedure;
+       protected static SyncMultiProcedure emptyProcedureMultiReadEntry = emptySyncMultiProcedure;
+       protected static AsyncMultiProcedure emptyProcedureAsyncMultiReadEntry = emptyAsyncMultiProcedure;
+       protected static AsyncProcedure emptyProcedureExternalReadEntry = emptyAsyncProcedure;
+
+       static class AsyncProcedureWrapper<T> implements AsyncProcedure<T> {
+
+               private AsyncProcedure<T> procedure;
+               private T result = null;
+               private Throwable throwable = null;
+               private Semaphore s = new Semaphore(0);
+
+               AsyncProcedureWrapper(AsyncProcedure<T> procedure) {
+                       this.procedure = procedure;
+               }
+
+               @Override
+               public void execute(AsyncReadGraph graph, T result) {
+                       if(procedure != null) procedure.execute(graph, result);
+                       this.result = result;
+                       s.release();
+               }
+
+               @Override
+               public void exception(AsyncReadGraph graph, Throwable throwable) {
+                       if(procedure != null) procedure.exception(graph, throwable);
+                       this.throwable = throwable;
+                       s.release();
+               }
+
+               public T get() throws DatabaseException {
+                       try {
+                               s.acquire();
+                       } catch (InterruptedException e) {
+                               e.printStackTrace();
+                       }
+                       if(throwable != null) {
+                               if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
+                               else throw new DatabaseException(throwable);
+                       } else {
+                               return result;
+                       }
+               }
+               
+       }
+
+       static class ExternalProcedureWrapper<T> implements AsyncProcedure<T> {
+
+               private Procedure<T> procedure;
+               private T result = null;
+               private Throwable throwable = null;
+
+               ExternalProcedureWrapper(Procedure<T> procedure) {
+                       this.procedure = procedure;
+               }
+
+               @Override
+               public void execute(AsyncReadGraph graph, T result) {
+                       if(procedure != null) procedure.execute(result);
+                       this.result = result;
+               }
+
+               @Override
+               public void exception(AsyncReadGraph graph, Throwable throwable) {
+                       if(procedure != null) procedure.exception(throwable);
+                       this.throwable = throwable;
+               }
+
+               public T get() throws DatabaseException {
+                       if(throwable != null) {
+                               if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
+                               else throw new DatabaseException(throwable);
+                       } else {
+                               return result;
+                       }
+               }
+
+       }
+
+
+       static class InternalProcedureWrapper<T> implements InternalProcedure<T> {
+
+               private InternalProcedure<T> procedure;
+               private T result = null;
+               private Throwable throwable = null;
+
+               InternalProcedureWrapper(InternalProcedure<T> procedure) {
+                       this.procedure = procedure;
+               }
+
+               @Override
+               public void execute(ReadGraphImpl graph, T result) throws DatabaseException {
+                       if(procedure != null) procedure.execute(graph, result);
+                       this.result = result;
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
+                       if(procedure != null) procedure.exception(graph, throwable);
+                       this.throwable = throwable;
+               }
+
+               public T get() throws DatabaseException {
+                       if(throwable != null) {
+                               if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
+                               else throw new DatabaseException(throwable);
+                       } else {
+                               return result;
+                       }
+               }
+
+       }
+
+       static class IntSetWrapper implements IntProcedure {
+
+               private IntProcedure procedure;
+               private final IntSet result;
+               private Throwable throwable = null;
+
+               IntSetWrapper(ReadGraphImpl graph, IntProcedure procedure) {
+                       this.procedure = procedure;
+                       result = new IntSet(graph.processor.querySupport);
+               }
+
+               @Override
+               public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
+                       if(procedure != null) procedure.execute(graph, i);
+                       result.add(i);
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
+                       if(procedure != null) procedure.exception(graph, throwable);
+                       this.throwable = throwable;
+               }
+
+               @Override
+               public void finished(ReadGraphImpl graph) throws DatabaseException {
+                       if(procedure != null) procedure.finished(graph);
+               }
+
+               public IntSet get() throws DatabaseException {
+                       if(throwable != null) {
+                               if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
+                               else throw new DatabaseException(throwable);
+                       } else {
+                               return result;
+                       }
+               }
+
+       }
+
+       static class TripleIntProcedureWrapper implements TripleIntProcedure {
+
+               private TripleIntProcedure procedure;
+               private IntArray result = new IntArray();
+               private Throwable throwable = null;
+
+               TripleIntProcedureWrapper(TripleIntProcedure procedure) {
+                       this.procedure = procedure;
+               }
+
+               @Override
+               public void execute(ReadGraphImpl graph, int i1, int i2, int i3) throws DatabaseException {
+                       if(procedure != null) procedure.execute(graph, i1, i2, i3);
+                       result.add(i1);
+                       result.add(i2);
+                       result.add(i3);
+               }
+
+               @Override
+               public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
+                       if(procedure != null) procedure.exception(graph, throwable);
+                       this.throwable = throwable;
+               }
+
+               @Override
+               public void finished(ReadGraphImpl graph) throws DatabaseException {
+                       if(procedure != null) procedure.finished(graph);
+               }
+
+               public IntArray get() throws DatabaseException {
+                       if(throwable != null) {
+                               if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
+                               else throw new DatabaseException(throwable);
+                       } else {
+                               return result;
+                       }
+               }
+
+       }
+
+       public static <T> T resultExternalReadEntry(ReadGraphImpl graph, ExternalRead r, CacheEntry parent, ListenerBase listener, Procedure<T> procedure) throws DatabaseException {
+               ExternalProcedureWrapper<T> wrap = new ExternalProcedureWrapper<>(procedure);
+               QueryCache.runnerExternalReadEntry(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static <T> T resultReadEntry(ReadGraphImpl graph, Read r, CacheEntry parent, ListenerBase listener, AsyncProcedure<T> procedure) throws DatabaseException {
+               AsyncProcedureWrapper<T> wrap = new AsyncProcedureWrapper<>(procedure);
+               QueryCache.runnerReadEntry(graph, r, parent, listener, wrap, true);
+               return wrap.get();
+       }
+
+       public static <T> T resultAsyncReadEntry(ReadGraphImpl graph, AsyncRead r, CacheEntry parent, ListenerBase listener, AsyncProcedure<T> procedure) throws DatabaseException {
+               AsyncProcedureWrapper<T> wrap = new AsyncProcedureWrapper<>(procedure);
+               QueryCache.runnerAsyncReadEntry(graph, r, parent, listener, wrap, true);
+               return wrap.get();
+       }
+
+       public static byte[] resultValueQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<byte[]> wrap = new InternalProcedureWrapper<>(null);
+               QueryCache.runnerValueQuery(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static RelationInfo resultRelationInfoQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<RelationInfo> wrap = new InternalProcedureWrapper<>(null);
+               QueryCache.runnerRelationInfoQuery(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static IntSet resultSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<IntSet> wrap = new InternalProcedureWrapper<>(null);
+               QueryCache.runnerSuperRelations(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static IntSet resultSuperTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<IntSet> wrap = new InternalProcedureWrapper<>(null);
+               QueryCache.runnerSuperTypes(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static IntSet resultTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<IntSet> wrap = new InternalProcedureWrapper<>(null);
+               QueryCache.runnerTypes(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static IntSet resultPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<IntSet> wrap = new InternalProcedureWrapper<>(null);
+               QueryCache.runnerPredicates(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static IntSet resultDirectPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<IntSet> wrap = new InternalProcedureWrapper<>(null);
+               QueryCache.runnerDirectPredicates(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static IntArray resultAssertedStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               TripleIntProcedureWrapper wrap = new TripleIntProcedureWrapper(null);
+               QueryCache.runnerAssertedStatements(graph, r1, r2, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static Integer resultURIToResource(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<Integer> wrap = new InternalProcedureWrapper<Integer>(null);
+               QueryCache.runnerURIToResource(graph, id, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       public static ObjectResourceIdMap<String> resultChildMap(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException {
+               InternalProcedureWrapper<ObjectResourceIdMap<String>> wrap = new InternalProcedureWrapper<ObjectResourceIdMap<String>>(null);
+               QueryCache.runnerChildMap(graph, r, parent, listener, wrap);
+               return wrap.get();
+       }
+
+       static boolean shouldCache(QueryProcessor processor, int r) {
+               return processor.isImmutable(r);
+       }
+
+       static boolean shouldCache(QueryProcessor processor, int r, int r2) {
+               return processor.isImmutable(r);
+       }
+
+       static boolean shouldCache(QueryProcessor processor, Object o) {
+               return false;
+       }
+
+}
\ No newline at end of file