]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java
Generate parts of db client query code
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / QueryCache.java
index 2adc7c78bff6fc0836d25ac373f0829987ca7ff1..4be12da47d582b08cf0d6dfe16129d42650c7509 100644 (file)
 package org.simantics.db.impl.query;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.simantics.db.AsyncReadGraph;
 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.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.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;
-
-public class QueryCache {
-
-       final public UnaryQueryHashMap<IntProcedure>                      directPredicatesMap;
-       final public UnaryQueryHashMap<IntProcedure>                      principalTypesMap;
-       final public THashMap<String, URIToResource>                      uriToResourceMap;
-       final public THashMap<String, NamespaceIndex>                     namespaceIndexMap22;
-       final public UnaryQueryHashMap<IntProcedure>                      projectsMap;
-       final public UnaryQueryHashMap<InternalProcedure<RelationInfo>>   relationInfoMap;
-       final public UnaryQueryHashMap<InternalProcedure<IntSet>>         superTypesMap;
-       final public UnaryQueryHashMap<InternalProcedure<IntSet>>         typeHierarchyMap;
-       final public UnaryQueryHashMap<InternalProcedure<IntSet>>         superRelationsMap;
-       final public UnaryQueryHashMap<InternalProcedure<IntSet>>         typesMap;
-       final public UnaryQueryHashMap<InternalProcedure<byte[]>>         valueMap;
-       final public DoubleKeyQueryHashMap<IntProcedure>                     directObjectsMap;
-       final public DoubleKeyQueryHashMap<IntProcedure>                     objectsMap;
-       final public UnaryQueryHashMap<IntProcedure>                      orderedSetMap;
-       final public UnaryQueryHashMap<IntProcedure>                      predicatesMap;
-       final public DoubleKeyQueryHashMap<TripleIntProcedure>               statementsMap;
-       final public UnaryQueryHashMap<IntProcedure>                      assertedPredicatesMap;
-       final public BinaryQueryHashMap<TripleIntProcedure>               assertedStatementsMap;
-       final public StableHashMap<ExternalRead, ExternalReadEntry>            externalReadMap; 
-       final public StableHashMap<AsyncRead, AsyncReadEntry>                  asyncReadMap; 
-       final public StableHashMap<Read, ReadEntry>                            readMap;
-       final public StableHashMap<AsyncMultiRead, AsyncMultiReadEntry>        asyncMultiReadMap; 
-       final public StableHashMap<MultiRead, MultiReadEntry>                  multiReadMap; 
-
-       final THashMap<CacheEntry, ArrayList<ListenerEntry>>       listeners;
-
-       public QueryCache() {
-               directPredicatesMap = new UnaryQueryHashMap();
-               valueMap = new UnaryQueryHashMap();
-               principalTypesMap = new UnaryQueryHashMap();
-               uriToResourceMap = new THashMap<String, URIToResource>();
-               namespaceIndexMap22 = new THashMap<String, NamespaceIndex>();
-               projectsMap = new UnaryQueryHashMap();
-               relationInfoMap = 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 BinaryQueryHashMap();
-               asyncReadMap = new StableHashMap<AsyncRead, AsyncReadEntry>(); 
-               readMap = new StableHashMap<Read, ReadEntry>();
-               asyncMultiReadMap = new StableHashMap<AsyncMultiRead, AsyncMultiReadEntry>(); 
-               multiReadMap = new StableHashMap<MultiRead, MultiReadEntry>(); 
-               externalReadMap = new StableHashMap<ExternalRead, ExternalReadEntry>(); 
-               listeners = new THashMap<CacheEntry, ArrayList<ListenerEntry>>(10, 0.75f);
-       }
-       
-       public int requestHash(Object object) {
-               try {
-                       return object.hashCode();
-               } catch (Throwable t) {
-                       Logger.defaultLogError(t);
-                       return 0;
-               }
-       }
-
-       private CacheEntryBase getCached(Object query, int hash) {
-               if (query instanceof AsyncRead)
-                       return asyncReadMap.get(query, hash);
-               else if (query instanceof Read)
-                       return readMap.get(query, hash);
-               else if (query instanceof ExternalRead)
-                       return externalReadMap.get(query, hash);
-               else if (query instanceof AsyncMultiRead)
-                       return asyncMultiReadMap.get(query, hash);
-               throw new IllegalStateException();
-       }
-       
-       private CacheEntryBase createEntry(QuerySupport support, Object query, int hash) {
-
-               CacheEntryBase result;
-               if (query instanceof AsyncRead) {
-                       AsyncReadEntry entry = new AsyncReadEntry((AsyncRead)query);
-                       asyncReadMap.put((AsyncRead)query, entry, hash);
-                       result = entry;
-               } else if (query instanceof Read) {
-                       ReadEntry entry = new ReadEntry((Read)query);
-                       readMap.put((Read)query, entry, hash);
-                       result = entry;
-               } else if (query instanceof ExternalRead) {
-                       ExternalReadEntry entry = new ExternalReadEntry((ExternalRead)query);
-                       externalReadMap.put((ExternalRead)query, entry, hash);
-                       result = entry;
-               } else if (query instanceof AsyncMultiRead) {
-                       AsyncMultiReadEntry entry = new AsyncMultiReadEntry((AsyncMultiRead)query);
-                       asyncMultiReadMap.put((AsyncMultiRead)query, entry, hash);
-                       result = entry;
-               } else {
-                       throw new IllegalStateException();
-               }
-               
-               result.setPending();
-               result.clearResult(support);
-               
-               return result;
-               
-       }
-       
-       public final <T> Object runQuery(final ReadGraphImpl graph, final Object query, final CacheEntry parent, final ListenerBase listener, final Object procedure) throws DatabaseException {
-
-               int hash = requestHash(query);
-
-               CacheEntryBase entry =  getCached(query, hash);
-
-               if(parent == null && listener == null) {
-                       if(entry != null && (entry.isReady() || entry.isExcepted())) {
-                               return entry.performFromCache(graph, this, procedure);
-                       } else {
-                               return performQuery(graph, query, entry, null, procedure);
-                       }
-               }
-
-               if(entry == null) {
-                       entry = createEntry(graph.processor.querySupport, query, hash);
-                       return performForEach(graph, query, entry, parent, listener, procedure, false);
-
-               } else {
-
-                       if(entry.isPending()) {
-                               synchronized(entry) {
-                                       if(entry.isPending()) {
-                                           throw new IllegalStateException();
-                                               //                      final AsyncBarrierImpl parentBarrier = graph.state.barrier;
-                                               //                      if(entry.procs == null) entry.procs = new ArrayList<AsyncProcedure<T>>();
-                                               //                        entry.procs.add(new AsyncProcedure<T>() {
-                                               //
-                                               //                                                      @Override
-                                               //                                                      public void execute(AsyncReadGraph graph, T result) {
-                                               //                                                              procedure.execute(graph, result);
-                                               //                                                              parentBarrier.dec(query);
-                                               //                                                      }
-                                               //
-                                               //                                                      @Override
-                                               //                                                      public void exception(AsyncReadGraph graph, Throwable throwable) {
-                                               //                                                              procedure.exception(graph, throwable);
-                                               //                                                              parentBarrier.dec(query);
-                                               //                                                      }
-                                               //                              
-                                               //                        });
-//                                             if(graph.parent != null || listener != null) {
-//                                                     registerDependencies(graph, entry, parent, listener, procedure, false);
-//                                             }
-//
-//                                             query.perform(graph, procedure);
-//
-//                                             return;
-
-                                       }
-                               }
-                       }
-
-                       if(entry.isReady()) { 
-                               Object result = entry.performFromCache(graph, this, procedure);
-                               registerDependencies(graph, entry, parent, listener, procedure, false);
-                               return result;
-                       } else {
-                               return performForEach(graph, query, entry, parent, listener, procedure, false);
-                       }
-
-               }
-
-       }
-
-       public <T> Object performQuery(ReadGraphImpl parentGraph, final Object query_, final CacheEntryBase entry_, ListenerEntry listenerEntry, Object procedure_) throws DatabaseException {
-
-               ReadGraphImpl queryGraph = parentGraph.withParent(entry_);
-
-               if(query_ instanceof AsyncRead) {
-               
-                       AsyncRead<T> query = (AsyncRead<T>)query_;
-                       AsyncReadEntry<T> entry = (AsyncReadEntry<T>)entry_;
-                       AsyncProcedure<T> procedure = (AsyncProcedure<T>)procedure_;
-
-                       try {
-                               
-                               query.perform(queryGraph, new AsyncProcedure<T>() {
-       
-                                       @Override
-                                       public void execute(AsyncReadGraph returnGraph, T result) {
-                                               ReadGraphImpl impl = (ReadGraphImpl)returnGraph;
-                                               entry.addOrSet(parentGraph, result);
-                                               if(listenerEntry != null) {
-                                                       primeListenerEntry(listenerEntry, 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;
-
-               } else if (query_ instanceof Read) {
-                       
-                       Read query = (Read)query_;
-                       ReadEntry entry = (ReadEntry)entry_;
-
-                       entry.setPending();
-
-                       try {
-
-                               T result = (T)query.perform(queryGraph);
-                               entry.addOrSet(queryGraph, result);
-                               
-                               if(listenerEntry != null) primeListenerEntry(listenerEntry, result);
-
-                               return (T)entry.get(parentGraph, parentGraph.processor, procedure_);
-
-                       }  catch (Throwable t) {
-
-                               entry.except(t);
-                               return (T)entry.get(parentGraph, parentGraph.processor, procedure_);
-
-                       }
-                       
-               } else if (query_ instanceof ExternalRead) {
-                       
-                       ExternalRead query = (ExternalRead)query_;
-                       ExternalReadEntry entry = (ExternalReadEntry)entry_;
-                       Procedure<T> procedure = (Procedure<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(entry.isExcepted()) entry.setPending();
-                                               
-                                               if(used.compareAndSet(false, true)) {
-                                                       entry.addOrSet(parentGraph.processor, result);
-                                                       procedure.execute(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(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(t);
-                               return entry.getResult();
-
-                       }
-
-               } else if (query_ instanceof AsyncMultiRead) {
-                       
-                       AsyncMultiRead query = (AsyncMultiRead)query_;
-                       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();
-                               
-                       }
-
-               } else {
-
-                       throw new IllegalStateException();
-
-               }
-
-       }
-       
-       public <T> Object performFromCache(ReadGraphImpl parentGraph, Object query, CacheEntryBase entry_, ListenerEntry listenerEntry, Object procedure_) throws DatabaseException {
-
-               Object result = entry_.performFromCache(parentGraph, this, procedure_);
-               if(listenerEntry != null) {
-                       primeListenerEntry(listenerEntry, result);
-               }
-               return result;
-
-//             if(query instanceof AsyncRead) {
-//                     
-//                     AsyncProcedure<T> procedure = (AsyncProcedure<T>)procedure_;
-//
-//                     
-//                     return null;
-//
-//             } else if(query instanceof Read) {
-//                     
-//                     ReadEntry entry = (ReadEntry)entry_;
-//
-//                     T result = (T)entry.get(parentGraph, parentGraph.processor, procedure_); 
-//
-//                     if(listenerEntry != null) primeListenerEntry(listenerEntry, result);
-//
-//                     return result;
-//
-//             } else if(query instanceof ExternalRead) {
-//
-//                     ExternalReadEntry entry = (ExternalReadEntry)entry_;
-//                     Procedure<T> procedure = (Procedure<T>)procedure_;
-//
-//                     return entry.performFromCache(procedure);
-//                     
-//             } else if (query instanceof AsyncMultiRead) {
-//                     
-//                     AsyncMultiReadEntry entry = (AsyncMultiReadEntry)entry_;
-//                     AsyncMultiProcedure<T> procedure = (AsyncMultiProcedure<T>)procedure_;
-//
-//                     return entry.performFromCache(parentGraph, this, procedure);
-//                     
-//             } else {
-//                     
-//                     throw new IllegalStateException();
-//                     
-//             }
-
-       }
-       
-       public <T> Object performForEach(ReadGraphImpl parentGraph, final Object query, final CacheEntryBase entry, final CacheEntry parent, final ListenerBase base, final Object procedure,
-                       boolean inferredDependency) throws DatabaseException {
-
-//             if (DebugPolicy.PERFORM)
-//                     System.out.println("PE[ " + (query.hashCode() & THREAD_MASK) + "] " + query);
-
-//             assert (!dirty);
-//             assert (!collecting);
-
-               assert(!entry.isDiscarded());
-
-               final ListenerEntry listenerEntry = registerDependencies(parentGraph, entry, parent, base, procedure, inferredDependency);
-
-               // FRESH, REFUTED, EXCEPTED go here 
-               if (!entry.isReady()) {
-
-                       entry.setPending();
-
-//                     size++;
-
-                       return performQuery(parentGraph, query, entry, listenerEntry, procedure);
-
-//                     misses++;
-
-               } else {
-                       
-                       return performFromCache(parentGraph, query, entry, listenerEntry, procedure);
-
-//                     parentBarrier.dec(query);
-
-//                     hits++;
-
-               }
-
-       }
-       
-       synchronized public ListenerEntry registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) {
-
-               if (parent != null && !inferred) {
-                       try {
-                               if(!child.isImmutable(graph))
-                                       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 ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) {
-
-               assert (entry != null);
-
-               if (base.isDisposed())
-                       return null;
-
-               return addListener(entry, base, procedure);
-
-       }
-
-       private 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 : valueMap.values()) {
-                       result.add((CacheEntry) e);
-               }
-               for (Object e : directPredicatesMap.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 : readMap.values()) {
-                       if(e instanceof CacheEntry) {
-                               result.add((CacheEntry) e);
-                       } else {
-                               System.err.println("e=" + e);
-                       }
-               }
-               for (Object e : asyncReadMap.values()) {
-                       if(e instanceof CacheEntry) {
-                               result.add((CacheEntry) e);
-                       } else {
-                               System.err.println("e=" + e);
-                       }
-               }
-               for (Object e : externalReadMap.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 += principalTypesMap.size();
-               realSize += uriToResourceMap.size();
-               realSize += namespaceIndexMap22.size();
-               realSize += projectsMap.size();
-               
-               realSize += relationInfoMap.size();
-               realSize += superTypesMap.size();
-               realSize += typeHierarchyMap.size();
-               realSize += superRelationsMap.size();
-               realSize += typesMap.size();
-               
-               realSize += valueMap.size();
-               realSize += directObjectsMap.size();
-               realSize += objectsMap.size();
-               realSize += orderedSetMap.size();
-               realSize += predicatesMap.size();
-               
-               realSize += statementsMap.size();
-               realSize += assertedPredicatesMap.size();
-               realSize += assertedStatementsMap.size();
-               realSize += externalReadMap.size();
-               realSize += asyncReadMap.size();
-               
-               realSize += readMap.size();
-               realSize += asyncMultiReadMap.size();
-               realSize += multiReadMap.size();
-               
-               return realSize;
-               
-       }
-       
-       CacheCollectionResult allCaches(CacheCollectionResult result) {
-
-               int level = Integer.MAX_VALUE;
-               directPredicatesMap.values(level, result);
-               principalTypesMap.values(level, result);
-               for(CacheEntryBase e : uriToResourceMap.values())
-                       if(e.getLevel() <= level)
-                               result.add(e);
-               for(CacheEntryBase e : namespaceIndexMap22.values())
-                       if(e.getLevel() <= level)
-                               result.add(e);
-               projectsMap.values(level, result);
-               
-               relationInfoMap.values(level, result);
-               superTypesMap.values(level, result);
-               typeHierarchyMap.values(level, result);
-               superRelationsMap.values(level, result);
-               typesMap.values(level, result);
-
-               valueMap.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);
-               externalReadMap.values(level, result);
-               asyncReadMap.values(level, result);
-               
-               readMap.values(level, result);
-               asyncMultiReadMap.values(level, result);
-               multiReadMap.values(level, result);
-
-               return result;
-               
-       }
-       
-       public void scanPending() {
-
-               ArrayList<CacheEntry> entries = new ArrayList<CacheEntry>();
-
-               entries.addAll(directPredicatesMap.values());
-               entries.addAll(principalTypesMap.values());
-               entries.addAll(uriToResourceMap.values());
-               entries.addAll(namespaceIndexMap22.values());
-               entries.addAll(projectsMap.values());
-               entries.addAll(relationInfoMap.values());
-               entries.addAll(superTypesMap.values());
-               entries.addAll(superRelationsMap.values());
-               entries.addAll(typesMap.values());
-               entries.addAll(valueMap.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(externalReadMap.values());
-               entries.addAll(asyncReadMap.values());
-               entries.addAll(externalReadMap.values());
-               entries.addAll(readMap.values());
-               entries.addAll(asyncMultiReadMap.values());
-               entries.addAll(multiReadMap.values());
-               entries.addAll(readMap.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);
-                       }
-               }
-       }
-       
+import gnu.trove.map.hash.TObjectIntHashMap;
+
+public class QueryCache extends QueryCacheBase {
+
+    public QueryCache(QuerySupport querySupport, int threads) {
+        super(querySupport, threads);
+    }
+
+    Objects getOrCreateObjects(int r1, int r2) throws DatabaseException {
+        Objects existing = null;
+        synchronized(objectsMap) {
+            existing = (Objects)objectsMap.get(r1,r2);
+            if(existing == null) {
+                existing = new Objects(r1,r2);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                objectsMap.put(keyR2(r1,r2), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(Objects entry) {
+        synchronized(objectsMap) {
+            objectsMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            Objects.computeForEach(graph, r1,r2, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureObjects;
+        Objects entry = (Objects)cache.getOrCreateObjects(r1,r2);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            Objects.computeForEach(graph, r1,r2, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    Statements getOrCreateStatements(int r1, int r2) throws DatabaseException {
+        Statements existing = null;
+        synchronized(statementsMap) {
+            existing = (Statements)statementsMap.get(r1,r2);
+            if(existing == null) {
+                existing = new Statements(r1,r2);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                statementsMap.put(keyR2(r1,r2), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(Statements entry) {
+        synchronized(statementsMap) {
+            statementsMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, TripleIntProcedure procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            Statements.computeForEach(graph, r1,r2, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureStatements;
+        Statements entry = (Statements)cache.getOrCreateStatements(r1,r2);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            Statements.computeForEach(graph, r1,r2, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    DirectObjects getOrCreateDirectObjects(int r1, int r2) throws DatabaseException {
+        DirectObjects existing = null;
+        synchronized(directObjectsMap) {
+            existing = (DirectObjects)directObjectsMap.get(r1,r2);
+            if(existing == null) {
+                existing = new DirectObjects(r1,r2);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                directObjectsMap.put(keyR2(r1,r2), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(DirectObjects entry) {
+        synchronized(directObjectsMap) {
+            directObjectsMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerDirectObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            DirectObjects.computeForEach(graph, r1,r2, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureDirectObjects;
+        DirectObjects entry = (DirectObjects)cache.getOrCreateDirectObjects(r1,r2);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            DirectObjects.computeForEach(graph, r1,r2, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    RelationInfoQuery getOrCreateRelationInfoQuery(int r) throws DatabaseException {
+        RelationInfoQuery existing = null;
+        synchronized(relationInfoQueryMap) {
+            existing = (RelationInfoQuery)relationInfoQueryMap.get(r);
+            if(existing == null) {
+                existing = new RelationInfoQuery(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                relationInfoQueryMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(RelationInfoQuery entry) {
+        synchronized(relationInfoQueryMap) {
+            relationInfoQueryMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerRelationInfoQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<RelationInfo> procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            RelationInfoQuery.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureRelationInfoQuery;
+        RelationInfoQuery entry = (RelationInfoQuery)cache.getOrCreateRelationInfoQuery(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            RelationInfoQuery.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    URIToResource getOrCreateURIToResource(String id) throws DatabaseException {
+        URIToResource existing = null;
+        synchronized(uRIToResourceMap) {
+            existing = (URIToResource)uRIToResourceMap.get(id);
+            if(existing == null) {
+                existing = new URIToResource(id);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                uRIToResourceMap.put(keyID(id), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(URIToResource entry) {
+        synchronized(uRIToResourceMap) {
+            uRIToResourceMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerURIToResource(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener, InternalProcedure<Integer> procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            URIToResource.computeForEach(graph, id, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureURIToResource;
+        URIToResource entry = (URIToResource)cache.getOrCreateURIToResource(id);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            URIToResource.computeForEach(graph, id, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    ValueQuery getOrCreateValueQuery(int r) throws DatabaseException {
+        ValueQuery existing = null;
+        synchronized(valueQueryMap) {
+            existing = (ValueQuery)valueQueryMap.get(r);
+            if(existing == null) {
+                existing = new ValueQuery(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                valueQueryMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(ValueQuery entry) {
+        synchronized(valueQueryMap) {
+            valueQueryMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerValueQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<byte[]> procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            ValueQuery.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureValueQuery;
+        ValueQuery entry = (ValueQuery)cache.getOrCreateValueQuery(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            ValueQuery.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    OrderedSet getOrCreateOrderedSet(int r) throws DatabaseException {
+        OrderedSet existing = null;
+        synchronized(orderedSetMap) {
+            existing = (OrderedSet)orderedSetMap.get(r);
+            if(existing == null) {
+                existing = new OrderedSet(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                orderedSetMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(OrderedSet entry) {
+        synchronized(orderedSetMap) {
+            orderedSetMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerOrderedSet(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            OrderedSet.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureOrderedSet;
+        OrderedSet entry = (OrderedSet)cache.getOrCreateOrderedSet(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            OrderedSet.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    PrincipalTypes getOrCreatePrincipalTypes(int r) throws DatabaseException {
+        PrincipalTypes existing = null;
+        synchronized(principalTypesMap) {
+            existing = (PrincipalTypes)principalTypesMap.get(r);
+            if(existing == null) {
+                existing = new PrincipalTypes(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                principalTypesMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(PrincipalTypes entry) {
+        synchronized(principalTypesMap) {
+            principalTypesMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerPrincipalTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            PrincipalTypes.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedurePrincipalTypes;
+        PrincipalTypes entry = (PrincipalTypes)cache.getOrCreatePrincipalTypes(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            PrincipalTypes.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    DirectPredicates getOrCreateDirectPredicates(int r) throws DatabaseException {
+        DirectPredicates existing = null;
+        synchronized(directPredicatesMap) {
+            existing = (DirectPredicates)directPredicatesMap.get(r);
+            if(existing == null) {
+                existing = new DirectPredicates(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                directPredicatesMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(DirectPredicates entry) {
+        synchronized(directPredicatesMap) {
+            directPredicatesMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerDirectPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<IntSet> procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            DirectPredicates.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureDirectPredicates;
+        DirectPredicates entry = (DirectPredicates)cache.getOrCreateDirectPredicates(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            DirectPredicates.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    Predicates getOrCreatePredicates(int r) throws DatabaseException {
+        Predicates existing = null;
+        synchronized(predicatesMap) {
+            existing = (Predicates)predicatesMap.get(r);
+            if(existing == null) {
+                existing = new Predicates(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                predicatesMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(Predicates entry) {
+        synchronized(predicatesMap) {
+            predicatesMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<IntSet> procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            Predicates.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedurePredicates;
+        Predicates entry = (Predicates)cache.getOrCreatePredicates(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            Predicates.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    ReadEntry getOrCreateReadEntry(Read<?> r) throws DatabaseException {
+        ReadEntry existing = null;
+        synchronized(readEntryMap) {
+            existing = (ReadEntry)readEntryMap.get(r);
+            if(existing == null) {
+                existing = new ReadEntry(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                readEntryMap.put(id(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(ReadEntry entry) {
+        synchronized(readEntryMap) {
+            readEntryMap.remove(entry.request);
+        }
+    }
+    
+    static void runnerReadEntry(ReadGraphImpl graph, Read<?> r, CacheEntry parent, ListenerBase listener, AsyncProcedure procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            ReadEntry.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureReadEntry;
+        ReadEntry entry = (ReadEntry)cache.getOrCreateReadEntry(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            ReadEntry.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    Types getOrCreateTypes(int r) throws DatabaseException {
+        Types existing = null;
+        synchronized(typesMap) {
+            existing = (Types)typesMap.get(r);
+            if(existing == null) {
+                existing = new Types(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                typesMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(Types entry) {
+        synchronized(typesMap) {
+            typesMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<IntSet> procedure) throws DatabaseException {
+        if(parent == null && listener == null) {
+            Types.computeForEach(graph, r, null, procedure);
+            return;
+        }
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureTypes;
+        Types entry = (Types)cache.getOrCreateTypes(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            Types.computeForEach(graph, r, entry, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    AssertedStatements getOrCreateAssertedStatements(int r1, int r2) throws DatabaseException {
+        AssertedStatements existing = null;
+        synchronized(assertedStatementsMap) {
+            existing = (AssertedStatements)assertedStatementsMap.get(r1,r2);
+            if(existing == null) {
+                existing = new AssertedStatements(r1,r2);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                assertedStatementsMap.put(keyR2(r1,r2), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(AssertedStatements entry) {
+        synchronized(assertedStatementsMap) {
+            assertedStatementsMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerAssertedStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, TripleIntProcedure procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureAssertedStatements;
+        AssertedStatements entry = (AssertedStatements)cache.getOrCreateAssertedStatements(r1,r2);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    NamespaceIndex getOrCreateNamespaceIndex(String id) throws DatabaseException {
+        NamespaceIndex existing = null;
+        synchronized(namespaceIndexMap) {
+            existing = (NamespaceIndex)namespaceIndexMap.get(id);
+            if(existing == null) {
+                existing = new NamespaceIndex(id);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                namespaceIndexMap.put(keyID(id), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(NamespaceIndex entry) {
+        synchronized(namespaceIndexMap) {
+            namespaceIndexMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerNamespaceIndex(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener, InternalProcedure<TObjectIntHashMap<String>> procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureNamespaceIndex;
+        NamespaceIndex entry = (NamespaceIndex)cache.getOrCreateNamespaceIndex(id);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    AssertedPredicates getOrCreateAssertedPredicates(int r) throws DatabaseException {
+        AssertedPredicates existing = null;
+        synchronized(assertedPredicatesMap) {
+            existing = (AssertedPredicates)assertedPredicatesMap.get(r);
+            if(existing == null) {
+                existing = new AssertedPredicates(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                assertedPredicatesMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(AssertedPredicates entry) {
+        synchronized(assertedPredicatesMap) {
+            assertedPredicatesMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerAssertedPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureAssertedPredicates;
+        AssertedPredicates entry = (AssertedPredicates)cache.getOrCreateAssertedPredicates(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    DirectSuperRelations getOrCreateDirectSuperRelations(int r) throws DatabaseException {
+        DirectSuperRelations existing = null;
+        synchronized(directSuperRelationsMap) {
+            existing = (DirectSuperRelations)directSuperRelationsMap.get(r);
+            if(existing == null) {
+                existing = new DirectSuperRelations(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                directSuperRelationsMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(DirectSuperRelations entry) {
+        synchronized(directSuperRelationsMap) {
+            directSuperRelationsMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerDirectSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureDirectSuperRelations;
+        DirectSuperRelations entry = (DirectSuperRelations)cache.getOrCreateDirectSuperRelations(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    SuperTypes getOrCreateSuperTypes(int r) throws DatabaseException {
+        SuperTypes existing = null;
+        synchronized(superTypesMap) {
+            existing = (SuperTypes)superTypesMap.get(r);
+            if(existing == null) {
+                existing = new SuperTypes(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                superTypesMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(SuperTypes entry) {
+        synchronized(superTypesMap) {
+            superTypesMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerSuperTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<IntSet> procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureSuperTypes;
+        SuperTypes entry = (SuperTypes)cache.getOrCreateSuperTypes(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    TypeHierarchy getOrCreateTypeHierarchy(int r) throws DatabaseException {
+        TypeHierarchy existing = null;
+        synchronized(typeHierarchyMap) {
+            existing = (TypeHierarchy)typeHierarchyMap.get(r);
+            if(existing == null) {
+                existing = new TypeHierarchy(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                typeHierarchyMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(TypeHierarchy entry) {
+        synchronized(typeHierarchyMap) {
+            typeHierarchyMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerTypeHierarchy(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<IntSet> procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureTypeHierarchy;
+        TypeHierarchy entry = (TypeHierarchy)cache.getOrCreateTypeHierarchy(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    SuperRelations getOrCreateSuperRelations(int r) throws DatabaseException {
+        SuperRelations existing = null;
+        synchronized(superRelationsMap) {
+            existing = (SuperRelations)superRelationsMap.get(r);
+            if(existing == null) {
+                existing = new SuperRelations(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                superRelationsMap.put(keyR(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(SuperRelations entry) {
+        synchronized(superRelationsMap) {
+            superRelationsMap.remove(entry.id);
+        }
+    }
+    
+    static void runnerSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure<IntSet> procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureSuperRelations;
+        SuperRelations entry = (SuperRelations)cache.getOrCreateSuperRelations(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    AsyncReadEntry getOrCreateAsyncReadEntry(AsyncRead<?> r) throws DatabaseException {
+        AsyncReadEntry existing = null;
+        synchronized(asyncReadEntryMap) {
+            existing = (AsyncReadEntry)asyncReadEntryMap.get(r);
+            if(existing == null) {
+                existing = new AsyncReadEntry(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                asyncReadEntryMap.put(id(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(AsyncReadEntry entry) {
+        synchronized(asyncReadEntryMap) {
+            asyncReadEntryMap.remove(entry.request);
+        }
+    }
+    
+    static void runnerAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, CacheEntry parent, ListenerBase listener, AsyncProcedure procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureAsyncReadEntry;
+        AsyncReadEntry entry = (AsyncReadEntry)cache.getOrCreateAsyncReadEntry(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    MultiReadEntry getOrCreateMultiReadEntry(MultiRead<?> r) throws DatabaseException {
+        MultiReadEntry existing = null;
+        synchronized(multiReadEntryMap) {
+            existing = (MultiReadEntry)multiReadEntryMap.get(r);
+            if(existing == null) {
+                existing = new MultiReadEntry(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                multiReadEntryMap.put(id(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(MultiReadEntry entry) {
+        synchronized(multiReadEntryMap) {
+            multiReadEntryMap.remove(entry.request);
+        }
+    }
+    
+    static void runnerMultiReadEntry(ReadGraphImpl graph, MultiRead<?> r, CacheEntry parent, ListenerBase listener, AsyncMultiProcedure procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureMultiReadEntry;
+        MultiReadEntry entry = (MultiReadEntry)cache.getOrCreateMultiReadEntry(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    AsyncMultiReadEntry getOrCreateAsyncMultiReadEntry(AsyncMultiRead<?> r) throws DatabaseException {
+        AsyncMultiReadEntry existing = null;
+        synchronized(asyncMultiReadEntryMap) {
+            existing = (AsyncMultiReadEntry)asyncMultiReadEntryMap.get(r);
+            if(existing == null) {
+                existing = new AsyncMultiReadEntry(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                asyncMultiReadEntryMap.put(id(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(AsyncMultiReadEntry entry) {
+        synchronized(asyncMultiReadEntryMap) {
+            asyncMultiReadEntryMap.remove(entry.request);
+        }
+    }
+    
+    static void runnerAsyncMultiReadEntry(ReadGraphImpl graph, AsyncMultiRead<?> r, CacheEntry parent, ListenerBase listener, AsyncMultiProcedure procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureAsyncMultiReadEntry;
+        AsyncMultiReadEntry entry = (AsyncMultiReadEntry)cache.getOrCreateAsyncMultiReadEntry(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
+    ExternalReadEntry getOrCreateExternalReadEntry(ExternalRead<?> r) throws DatabaseException {
+        ExternalReadEntry existing = null;
+        synchronized(externalReadEntryMap) {
+            existing = (ExternalReadEntry)externalReadEntryMap.get(r);
+            if(existing == null) {
+                existing = new ExternalReadEntry(r);
+                existing.clearResult(querySupport);
+                existing.setPending();
+                externalReadEntryMap.put(id(r), existing);
+                return existing;
+            }
+            if(existing.requiresComputation()) {
+                existing.setPending();
+                return existing;
+            }
+        }
+        if(existing.isPending()) waitPending(existing);
+        return existing;
+    }
+    
+    void remove(ExternalReadEntry entry) {
+        synchronized(externalReadEntryMap) {
+            externalReadEntryMap.remove(entry.request);
+        }
+    }
+    
+    static void runnerExternalReadEntry(ReadGraphImpl graph, ExternalRead<?> r, CacheEntry parent, ListenerBase listener, AsyncProcedure procedure) throws DatabaseException {
+        QueryCache cache  = graph.processor.cache;
+        if(procedure == null) procedure = emptyProcedureExternalReadEntry;
+        ExternalReadEntry entry = (ExternalReadEntry)cache.getOrCreateExternalReadEntry(r);
+        ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);
+        if(entry.isReady()) entry.performFromCache(graph, procedure);
+        else {
+            entry.compute(graph, procedure);
+            if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult());
+        }
+    }
+    
 }