]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/DirectQuerySupportImpl.java
Multiple reader thread support for db client
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / DirectQuerySupportImpl.java
index 0b640861e1d6af93255b25114c429b2f374ce54f..06c5ebfed22a0f3c3d51b727e1c0e1dc2338313a 100644 (file)
@@ -1,12 +1,9 @@
 package fi.vtt.simantics.procore.internal;
 
-import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.DirectStatements;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.RelationInfo;
 import org.simantics.db.Resource;
-import org.simantics.db.common.procedure.wrapper.NoneToAsyncProcedure;
-import org.simantics.db.common.procedure.wrapper.SyncToAsyncProcedure;
 import org.simantics.db.exception.AssumptionException;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.exception.NoSingleResultException;
@@ -19,18 +16,15 @@ import org.simantics.db.impl.ForPossibleRelatedValueProcedure;
 import org.simantics.db.impl.ResourceImpl;
 import org.simantics.db.impl.TransientGraph;
 import org.simantics.db.impl.graph.ReadGraphImpl;
-import org.simantics.db.procedure.AsyncContextMultiProcedure;
-import org.simantics.db.procedure.AsyncContextProcedure;
-import org.simantics.db.procedure.AsyncMultiProcedure;
-import org.simantics.db.procedure.AsyncProcedure;
-import org.simantics.db.procedure.Procedure;
+import org.simantics.db.procedure.SyncContextMultiProcedure;
+import org.simantics.db.procedure.SyncContextProcedure;
+import org.simantics.db.procedure.SyncMultiProcedure;
 import org.simantics.db.procedure.SyncProcedure;
 import org.simantics.db.procore.cluster.ClusterBig;
 import org.simantics.db.procore.cluster.ClusterImpl;
 import org.simantics.db.procore.cluster.ClusterSmall;
 import org.simantics.db.procore.cluster.ResourceTableSmall;
 import org.simantics.db.procore.cluster.ValueTableSmall;
-import org.simantics.db.request.AsyncRead;
 import org.simantics.db.service.DirectQuerySupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,166 +40,61 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
        }
 
        @Override
-       final public void forEachDirectPersistentStatement(AsyncReadGraph graph, final Resource subject, final AsyncProcedure<DirectStatements> procedure) {
+       final public DirectStatements getDirectPersistentStatements(ReadGraph graph, final Resource subject) {
                ReadGraphImpl impl = (ReadGraphImpl)graph;
-               impl.processor.forEachDirectStatement(impl, subject, procedure, true);
+               return impl.processor.getDirectStatements(impl, subject, true);
        }
 
        @Override
-       final public void forEachDirectStatement(AsyncReadGraph graph, final Resource subject, final AsyncProcedure<DirectStatements> procedure) {
+       final public DirectStatements getDirectStatements(ReadGraph graph, final Resource subject) {
                ReadGraphImpl impl = (ReadGraphImpl)graph;
-               impl.processor.forEachDirectStatement(impl, subject, procedure, false);
+               return impl.processor.getDirectStatements(impl, subject, false);
        }
 
        @Override
-       public void forEachDirectStatement(AsyncReadGraph graph, Resource subject, SyncProcedure<DirectStatements> procedure) {
-               forEachDirectStatement(graph, subject, new SyncToAsyncProcedure<DirectStatements>(procedure));
-       }
-
-       @Override
-       public void forEachDirectStatement(AsyncReadGraph graph, Resource subject, Procedure<DirectStatements> procedure) {
+       public RelationInfo getRelationInfo(ReadGraph graph, Resource subject) throws DatabaseException {
                ReadGraphImpl impl = (ReadGraphImpl)graph;
-               impl.processor.forEachDirectStatement(impl, subject, procedure);
+               return impl.processor.getRelationInfo(impl, subject);
        }
 
        @Override
-       public void forRelationInfo(AsyncReadGraph graph, Resource subject, AsyncProcedure<RelationInfo> procedure) {
-               ReadGraphImpl impl = (ReadGraphImpl)graph;
-               impl.processor.forRelationInfo(impl, subject, procedure);
-       }
+       public SyncMultiProcedure<Resource> compileForEachObject(ReadGraph graph, final Resource relation, SyncMultiProcedure<Resource> user) throws DatabaseException {
 
-       @Override
-       public void forRelationInfo(AsyncReadGraph graph, Resource subject, SyncProcedure<RelationInfo> procedure) {
-               forRelationInfo(graph, subject, new SyncToAsyncProcedure<RelationInfo>(procedure));
-       }
+               RelationInfo info = getRelationInfo(graph, relation);
+               final int predicateKey = ((ResourceImpl)relation).id;
+               return new ForEachObjectProcedure(predicateKey, info, session.queryProvider2, user);
 
-       @Override
-       public void forRelationInfo(AsyncReadGraph graph, Resource subject, Procedure<RelationInfo> procedure) {
-               forRelationInfo(graph, subject, new NoneToAsyncProcedure<RelationInfo>(procedure));
        }
 
        @Override
-       public AsyncMultiProcedure<Resource> compileForEachObject(ReadGraph graph, final Resource relation, AsyncMultiProcedure<Resource> user) {
-               
-               try {
-                       RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
+       public <C> SyncContextMultiProcedure<C, Resource> compileForEachObject(ReadGraph graph, final Resource relation, SyncContextMultiProcedure<C, Resource> user) throws DatabaseException {
 
-                               @Override
-                               public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
-                                       forRelationInfo(graph, relation, procedure);
-                               }
-
-                @Override
-                   public int threadHash() {
-                       return hashCode();
-                   }
+               RelationInfo info = getRelationInfo(graph, relation);
+               final int predicateKey = ((ResourceImpl)relation).id;
+               return new ForEachObjectContextProcedure<C>(predicateKey, info, session.queryProvider2, user);
 
-                               @Override
-                               public int getFlags() {
-                                       return 0;
-                               }
-
-                       });
-               final int predicateKey = ((ResourceImpl)relation).id;
-                       return new ForEachObjectProcedure(predicateKey, info, session.queryProvider2, user);
-               } catch (DatabaseException e) {
-                       return null;
-               }               
-        
        }
 
        @Override
-       public <C> AsyncContextMultiProcedure<C, Resource> compileForEachObject(ReadGraph graph, final Resource relation, AsyncContextMultiProcedure<C, Resource> user) {
-               
-               try {
-                       RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
-
-                               @Override
-                               public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
-                                       forRelationInfo(graph, relation, procedure);
-                               }
+       public <T> SyncProcedure<T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, SyncProcedure<T> user) throws DatabaseException {
 
-                @Override
-                   public int threadHash() {
-                       return hashCode();
-                   }
+               RelationInfo info = getRelationInfo(graph, relation);
+               final int predicateKey = ((ResourceImpl)relation).id;
+               return new ForPossibleRelatedValueProcedure<T>(predicateKey, info, user);
 
-                               @Override
-                               public int getFlags() {
-                                       return 0;
-                               }
-
-                       });
-               final int predicateKey = ((ResourceImpl)relation).id;
-                       return new ForEachObjectContextProcedure<C>(predicateKey, info, session.queryProvider2, user);
-               } catch (DatabaseException e) {
-                       return null;
-               }               
-        
-       }
-       
-       @Override
-       public <T> AsyncProcedure<T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, AsyncProcedure<T> user) {
-               
-               try {
-                       RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
-
-                               @Override
-                               public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
-                                       forRelationInfo(graph, relation, procedure);
-                               }
-
-                @Override
-                   public int threadHash() {
-                       return hashCode();
-                   }
-
-                               @Override
-                               public int getFlags() {
-                                       return 0;
-                               }
-
-                       });
-               final int predicateKey = ((ResourceImpl)relation).id;
-                       return new ForPossibleRelatedValueProcedure<T>(predicateKey, info, user);
-               } catch (DatabaseException e) {
-                       return null;
-               }               
-        
        }
 
        @Override
-       public <C, T> AsyncContextProcedure<C, T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, AsyncContextProcedure<C, T> user) {
-               
-               try {
-                       RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
+       public <C, T> SyncContextProcedure<C, T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, SyncContextProcedure<C, T> user) throws DatabaseException {
 
-                               @Override
-                               public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
-                                       forRelationInfo(graph, relation, procedure);
-                               }
-
-                @Override
-                   public int threadHash() {
-                       return hashCode();
-                   }
+               RelationInfo info = getRelationInfo(graph, relation);
+               final int predicateKey = ((ResourceImpl)relation).id;
+               return new ForPossibleRelatedValueContextProcedure<C, T>(predicateKey, info, user);
 
-                               @Override
-                               public int getFlags() {
-                                       return 0;
-                               }
-
-                       });
-               final int predicateKey = ((ResourceImpl)relation).id;
-                       return new ForPossibleRelatedValueContextProcedure<C, T>(predicateKey, info, user);
-               } catch (DatabaseException e) {
-                       return null;
-               }               
-        
        }
-       
+
        @Override
-       public void forEachObjectCompiled(AsyncReadGraph graph, Resource subject, final AsyncMultiProcedure<Resource> procedure) {
+       public void forEachObjectCompiled(ReadGraph graph, Resource subject, final SyncMultiProcedure<Resource> procedure) {
                
         assert(subject != null);
         
@@ -261,7 +150,7 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
        }
 
        @Override
-       public <C> void forEachObjectCompiled(AsyncReadGraph graph, Resource subject, C context, final AsyncContextMultiProcedure<C, Resource> procedure) {
+       public <C> void forEachObjectCompiled(ReadGraph graph, Resource subject, C context, final SyncContextMultiProcedure<C, Resource> procedure) {
                
                assert(subject != null);
 
@@ -283,9 +172,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                }
                
        }
-       
+
        @Override
-       public <T> void forPossibleRelatedValueCompiled(AsyncReadGraph graph, Resource subject, final AsyncProcedure<T> procedure) {
+       public <T> void forPossibleRelatedValueCompiled(ReadGraph graph, Resource subject, final SyncProcedure<T> procedure) {
                
                assert(subject != null);
 
@@ -302,11 +191,24 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
         
 //        if(callerThread == suggestSchedule) {
                
-               if(info.isFunctional) {
-                       getRelatedValue4(impl, subjectId, proc);
-               } else {
-                       getRelatedValue4(impl, subjectId, proc);
+//             if(info.isFunctional) {
+        try {
+               T result = getRelatedValue4(impl, subjectId, proc);
+               try {
+                       proc.execute(graph, result);
+               } catch (DatabaseException e2) {
+                       LOGGER.error("Unexpected exception while handling related value", e2);
                }
+        } catch (DatabaseException e) {
+               try {
+                       proc.exception(graph, e);
+               } catch (DatabaseException e2) {
+                       LOGGER.error("Unexpected exception while handling related value", e2);
+               }
+        }
+//             } else {
+//                     getRelatedValue4(impl, subjectId, proc);
+//             }
                
 //        } else {
 //             
@@ -341,7 +243,7 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
        }
 
        @Override
-       public <C, T> void forPossibleRelatedValueCompiled(AsyncReadGraph graph, Resource subject, C context, final AsyncContextProcedure<C, T> procedure) {
+       public <C, T> void forPossibleRelatedValueCompiled(ReadGraph graph, Resource subject, C context, final SyncContextProcedure<C, T> procedure) {
                
                assert(subject != null);
 
@@ -356,15 +258,21 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
         
 //        impl.inc();
                
-        if(info.isFunctional) {
-               getRelatedValue4(impl, subjectId, context, proc);
-        } else {
-               getRelatedValue4(impl, subjectId, context, proc);
-        }
+//        if(info.isFunctional) {
+//        } else {
+//             getRelatedValue4(impl, subjectId, context, proc);
+//        }
+
+               try {
+                       T result = getRelatedValue4(impl, subjectId, context, proc);
+               proc.execute(graph, context, result);
+               } catch (DatabaseException e) {
+               proc.execute(graph, context, null);
+               }
                
        }
        
-       @Override
+/*     @Override
        public <T> void forPossibleType(final AsyncReadGraph graph, Resource subject, final AsyncProcedure<Resource> procedure) {
                
         assert(subject != null);
@@ -413,9 +321,11 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
        
                
        }
+       
+       */
 
        @Override
-       public <C> void forPossibleDirectType(final AsyncReadGraph graph, Resource subject, final C context, final AsyncContextProcedure<C, Resource> procedure) {
+       public <C> void forPossibleDirectType(final ReadGraph graph, Resource subject, final C context, final SyncContextProcedure<C, Resource> procedure) {
                
         assert(subject != null);
 
@@ -447,7 +357,7 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
 //                                             impl.state.dec(0);
                                                
                                        } catch (DatabaseException e) {
-                                               e.printStackTrace();
+                                               LOGGER.error("forPossibleDirectType requestCluster callback failed", e);
                                        }
                
                                        }
@@ -472,15 +382,14 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                
         } catch (Throwable t) {
 
-               t.printStackTrace();
+               LOGGER.error("forPossibleDirectType failed unexpectedly", t);
                procedure.execute(graph, context, null);
                
         }
                
        }
        
-       
-       private <C, T> void getRelatedValue4(final ReadGraphImpl graph, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
+       private <C, T> T getRelatedValue4(final ReadGraphImpl graph, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) throws DatabaseException {
                
                int result = 0;
                
@@ -489,18 +398,14 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
-                                   g -> getRelatedValue4(g, subject, context, procedure)
-                               );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
+                           return getRelatedValue4(graph, subject, context, procedure);
                        }
                        
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                 for (int id : g.getObjects(subject, predicate)) {
                        if(result != 0) {
-                               procedure.exception(graph, new DatabaseException("Multiple objects"));
-//                             graph.dec();
-                               return;
+                               throw new DatabaseException("Multiple objects");
                        } else {
                                result = id;
                        }
@@ -508,121 +413,93 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                        }
                        
                        if(result == 0) {
-                               
-                       procedure.exception(graph, new DatabaseException("No objects for " + subject ));
-//                     graph.dec();
-                       return;
-                       
+                               throw new DatabaseException("No objects for " + subject );
                        } else {
-                               
-                               getValue4(graph, null, result, context, procedure);
-                               return;
-                               
+                               return getValue4(graph, null, result, context, procedure);
                        }
                        
                } 
                
         final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
         if(!cluster.isLoaded()) {
-               cluster.load(session.clusterTranslator, () -> getRelatedValue4(graph, subject, context, procedure));
-               return;
+               cluster.load();
+               return getRelatedValue4(graph, subject, context, procedure);
         }
         
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
                        
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
-                                   g -> getRelatedValue4(g, subject, context, procedure)
-                               );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
+                               return getRelatedValue4(graph, subject, context, procedure);
                        }
                
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                 for (int id : g.getObjects(subject, predicate)) {
                        if(result != 0) {
-                               procedure.exception(graph, new DatabaseException("Multiple objects"));
-//                             graph.dec();
-                               return;
+                               throw new DatabaseException("Multiple objects");
                        } else {
                                result = id;
                        }
                 }
                        }
                        
-                       getRelatedDirectValue4(graph, cluster, subject, result, context, procedure);
+                       return getRelatedDirectValue4(graph, cluster, subject, result, context, procedure);
                        
                } else {
                        
-                       getRelatedDirectValue4(graph, cluster, subject, 0, context, procedure);
+                       return getRelatedDirectValue4(graph, cluster, subject, 0, context, procedure);
                        
                }
                
        }
        
-       private <T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
+       private <T> T getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) throws DatabaseException {
                
                Object result = null;
        
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, 
-                                   g -> getValue4(g, containerCluster, subject, procedure)
-                           );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
+                           return getValue4(graph, containerCluster, subject, procedure);
                        }
                        
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                                Object value = g.getValue(subject);
                                if(value != null) {
                                        if(result != null) {
-                                               procedure.exception(graph, new DatabaseException("Multiple values"));
-//                                             graph.dec();
-                                               return;
+                                               throw new DatabaseException("Multiple values");
                                        } else {
                                                result = value;
                                        }
                                }
                        }
-
-                       procedure.execute(graph, (T)"name");
-//                     graph.dec();
-                       return;
-
+                       
+                       return (T)"name";
+                       
                }
                
                ClusterImpl cluster = containerCluster;
                if(!containerCluster.contains(subject)) {
                        cluster = session.clusterTable.getClusterByResourceKey(subject);
                        if(!cluster.isLoaded()) {
-                               cluster.load(session.clusterTranslator, new Runnable() {
-
-                                       @Override
-                                       public void run() {
-                                               getValue4(graph, containerCluster, subject, procedure);
-                                       }
-
-                               });
-                               return;
+                               cluster.load();
+                               return getValue4(graph, containerCluster, subject, procedure);
                        }
                }
                
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
-                           g -> getValue4(g, containerCluster, subject, procedure)
-                           );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
+                           return getValue4(graph, containerCluster, subject, procedure);
                        }
                
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                                Object value = g.getValue(subject);
                                if(value != null) {
                                        if(result != null) {
-                                               procedure.exception(graph, new DatabaseException("Multiple values"));
-//                                             graph.dec();
-                                               return;
+                                               throw new DatabaseException("Multiple values");
                                        } else {
                                                result = value;
                                        }
@@ -630,93 +507,72 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                        }
                        
                        if(result != null) {
-                               
-                               procedure.execute(graph, (T)result);
-//                             graph.state.barrier.dec();
-                               
+                               return (T)result;
                        } else {
-                               
                                if(ClusterTypeEnum.SMALL == cluster.getType())
-                                       getDirectValue4(graph, (ClusterSmall)cluster, subject, procedure);
+                                       return getDirectValue4(graph, (ClusterSmall)cluster, subject);
                                else 
-                                       getDirectValue4(graph, (ClusterBig)cluster, subject, procedure);
+                                       return getDirectValue4(graph, (ClusterBig)cluster, subject);
                        }
 
                } else {
 
                        if(ClusterTypeEnum.SMALL == cluster.getType())
-                               getDirectValue4(graph, (ClusterSmall)cluster, subject, procedure);
+                               return getDirectValue4(graph, (ClusterSmall)cluster, subject);
                        else 
-                               getDirectValue4(graph, (ClusterBig)cluster, subject, procedure);
+                               return getDirectValue4(graph, (ClusterBig)cluster, subject);
 
                }
        
        }
        
-       private <C, T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
+       private <C, T> T getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) throws DatabaseException {
                
                Object result = null;
        
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
-                                   g -> getValue4(g, containerCluster, subject, context, procedure)
-                           );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
+                           return getValue4(graph, containerCluster, subject, context, procedure);
                        }
                        
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                                Object value = g.getValue(subject);
                                if(value != null) {
                                        if(result != null) {
-                                               procedure.exception(graph, new DatabaseException("Multiple values"));
-//                                             graph.dec();
-                                               return;
+                                               throw new DatabaseException("Multiple values");
                                        } else {
                                                result = value;
                                        }
                                }
                        }
 
-                       procedure.execute(graph, context, (T)"name");
-//                     graph.dec();
-                       return;
-
+                       return (T)"name";
+                       
                }
                
                ClusterImpl cluster = containerCluster;
                if(!containerCluster.contains(subject)) {
                        cluster = session.clusterTable.getClusterByResourceKey(subject);
                        if(!cluster.isLoaded()) {
-                               cluster.load(session.clusterTranslator, new Runnable() {
-
-                                       @Override
-                                       public void run() {
-                                               getValue4(graph, containerCluster, subject, context, procedure);
-                                       }
-
-                               });
-                               return;
+                               cluster.load();
+                               return getValue4(graph, containerCluster, subject, context, procedure);
                        }
                }
                
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
-                                    g -> getValue4(g, containerCluster, subject, context, procedure)
-                           );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
+                           return getValue4(graph, containerCluster, subject, context, procedure);
                        }
                
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                                Object value = g.getValue(subject);
                                if(value != null) {
                                        if(result != null) {
-                                               procedure.exception(graph, new DatabaseException("Multiple values"));
-//                                             graph.dec();
-                                               return;
+                                               throw new DatabaseException("Multiple values");
                                        } else {
                                                result = value;
                                        }
@@ -724,84 +580,64 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                        }
                        
                        if(result != null) {
-                               
-                               procedure.execute(graph, context, (T)result);
-//                             graph.state.barrier.dec();
-                               
+                               return (T)result;
                        } else {
-                               
                                if(ClusterTypeEnum.SMALL == cluster.getType())
-                                       getDirectValue4(graph, (ClusterSmall)cluster, subject, context, procedure);
+                                       return getDirectValue4(graph, (ClusterSmall)cluster, subject);
                                else 
-                                       getDirectValue4(graph, (ClusterBig)cluster, subject, context, procedure);
+                                       return getDirectValue4(graph, (ClusterBig)cluster, subject);
                        }
 
                } else {
 
                        if(ClusterTypeEnum.SMALL == cluster.getType())
-                               getDirectValue4(graph, (ClusterSmall)cluster, subject, context, procedure);
+                               return getDirectValue4(graph, (ClusterSmall)cluster, subject);
                        else 
-                               getDirectValue4(graph, (ClusterBig)cluster, subject, context, procedure);
+                               return getDirectValue4(graph, (ClusterBig)cluster, subject);
 
                }
        
        }
 
-       private <T> void getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final ForPossibleRelatedValueProcedure<T> procedure) {
-
-               try {
+       private <T> T getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final ForPossibleRelatedValueProcedure<T> procedure) throws DatabaseException {
 
-                       int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
-                       if(so == 0) {
-                               if(result == 0) {
-                                       procedure.exception(graph, new DatabaseException("No objects " + subject + " " + procedure.predicateKey));
-//                                     graph.dec();
-                               } else {
-                                       getValue4(graph, cluster, result, procedure);
-                               }
+               int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
+               if(so == 0) {
+                       if(result == 0) {
+                               throw new DatabaseException("No objects " + subject + " " + procedure.predicateKey);
                        } else {
-                               if(result == 0) {
-                                       getValue4(graph, cluster, so, procedure);
-                               } else {
-                                       procedure.exception(graph, new DatabaseException("Multiple objects"));
-//                                     graph.dec();
-                               }
+                               return getValue4(graph, cluster, result, procedure);
+                       }
+               } else {
+                       if(result == 0) {
+                               return getValue4(graph, cluster, so, procedure);
+                       } else {
+                               throw new DatabaseException("Multiple objects");
                        }
-
-               } catch (DatabaseException e) {
-                       e.printStackTrace();
                }
-               
-       }
-
-       private <C, T> void getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
 
-               try {
+       }
+       
+       private <C, T> T getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) throws DatabaseException {
 
-                       int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
-                       if(so == 0) {
-                               if(result == 0) {
-                                       procedure.exception(graph, new NoSingleResultException("No objects " + subject + " " + procedure.predicateKey, result));
-//                                     graph.dec();
-                               } else {
-                                       getValue4(graph, cluster, result, context, procedure);
-                               }
+               int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
+               if(so == 0) {
+                       if(result == 0) {
+                               throw new NoSingleResultException("No objects " + subject + " " + procedure.predicateKey, result);
                        } else {
-                               if(result == 0) {
-                                       getValue4(graph, cluster, so, context, procedure);
-                               } else {
-                                       procedure.exception(graph, new NoSingleResultException("Multiple objects for " + subject + " " + procedure.predicateKey, result));
-//                                     graph.dec();
-                               }
+                               return getValue4(graph, cluster, result, context, procedure);
+                       }
+               } else {
+                       if(result == 0) {
+                               return getValue4(graph, cluster, so, context, procedure);
+                       } else {
+                               throw new NoSingleResultException("Multiple objects for " + subject + " " + procedure.predicateKey, result);
                        }
-
-               } catch (DatabaseException e) {
-                       LOGGER.error("Could not compute related value for subject {} with predicate {}", subject, procedure.predicateKey);
                }
                
        }
        
-       public <T> void getRelatedValue4(final ReadGraphImpl graph, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
+       public <T> T getRelatedValue4(final ReadGraphImpl graph, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) throws DatabaseException {
                
                int result = 0;
                
@@ -810,18 +646,14 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
-                                   g -> getRelatedValue4(g, subject, procedure)
-                           );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
+                           return getRelatedValue4(graph, subject, procedure);
                        }
                        
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                 for (int id : g.getObjects(subject, predicate)) {
                        if(result != 0) {
-                               procedure.exception(graph, new DatabaseException("Multiple objects"));
-//                             graph.dec();
-                               return;
+                               throw new DatabaseException("Multiple objects");
                        } else {
                                result = id;
                        }
@@ -829,64 +661,47 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                        }
                        
                        if(result == 0) {
-                               
-                       procedure.exception(graph, new DatabaseException("No objects for " + subject ));
-//                     graph.dec();
-                       return;
-                       
+                               throw new DatabaseException("No objects for " + subject );
                        } else {
-                               
-                               getValue4(graph, null, result, procedure);
-                               return;
-                               
+                               return getValue4(graph, null, result, procedure);
                        }
                        
                } 
                
         final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
         if(!cluster.isLoaded()) {
-               cluster.load(session.clusterTranslator, new Runnable() {
-
-                               @Override
-                               public void run() {
-                                       getRelatedValue4(graph, subject, procedure);
-                               }
-                       
-               });
-               return;
+               cluster.load();
+               return getRelatedValue4(graph, subject, procedure);
         }
         
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
                        
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
-                                   g -> getRelatedValue4(graph, subject, procedure)
-                           );
-                               return;
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
+                           return getRelatedValue4(graph, subject, procedure);
                        }
                
                        for(TransientGraph g : session.virtualGraphServerSupport.providers) {
                 for (int id : g.getObjects(subject, predicate)) {
                        if(result != 0) {
-                               procedure.exception(graph, new DatabaseException("Multiple objects"));
-//                             graph.dec();
-                               return;
+                               throw new DatabaseException("Multiple objects");
                        } else {
                                result = id;
                        }
                 }
                        }
                        
-                       getRelatedDirectValue4(graph, cluster, subject, result, procedure);
+                       return getRelatedDirectValue4(graph, cluster, subject, result, procedure);
                        
                } else {
                        
-                       getRelatedDirectValue4(graph, cluster, subject, 0, procedure);
+                       return getRelatedDirectValue4(graph, cluster, subject, 0, procedure);
                        
                }
                
        }
-       
+
+       /*
        private <C, T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
                
                try {
@@ -900,40 +715,16 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
 //             graph.dec();
                
        }
+       */
 
-       private <T> void getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
-               
-               try {
-                       byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
-                       T value = (T)utf(bytes);
-                       procedure.execute(graph, value);
-               } catch (DatabaseException e) {
-                       procedure.execute(graph, null);
-               }
-
-//             graph.dec();
-               
-       }
+       private <T> T getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject) throws DatabaseException {
 
-       private <C, T> void getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
-               
-               try {
-                       byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
-                       if(bytes == null) {
-                               procedure.execute(graph, context, null);
-                       } else {
-                               T value = (T)utf(bytes);
-                               procedure.execute(graph, context, value);
-                       }
-               } catch (DatabaseException e) {
-                       procedure.execute(graph, context, null);
-               }
+               byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
+               return (T)utf(bytes);
 
-//             graph.dec();
-               
        }
-       
-       private <T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
+
+       private <T> T getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject) throws DatabaseException {
 
                ResourceTableSmall rt = cluster.resourceTable;
                ValueTableSmall vt = cluster.valueTable;
@@ -941,25 +732,26 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                byte[] bs = vt.table;
                long[] ls = rt.table;
 
-               int index = ((subject&0xFFFF) << 1) - 1 + rt.offset;
+               int index = ((subject&0xFFF) << 1) - 1 + rt.offset;
 
                int valueIndex = (int)(ls[index] >>> 24) & 0x3FFFFF + vt.offset;
 
                int size = (int)bs[valueIndex++]-1;
+               if(size <= 0) {
+                       throw new DatabaseException("No value for " + subject); 
+               }
+               
                char[] chars = new char[size];
                valueIndex++;
                for(int i=0;i<size;i++) {
                        chars[i] = (char)bs[valueIndex++];
                }
 
-               T value = (T)new String(chars);
+               return (T)new String(chars);
 
-               procedure.execute(graph, value);
-//             graph.dec();
-               
        }
 
-       final private String utf(byte[] bytes) throws AssumptionException {
+       private final String utf(byte[] bytes) throws AssumptionException {
 
                if(bytes == null) return null;