]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/DirectQuerySupportImpl.java
Backported b75a6bbc for release/1.32.0.2
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / DirectQuerySupportImpl.java
1 package fi.vtt.simantics.procore.internal;
2
3 import org.simantics.db.AsyncReadGraph;
4 import org.simantics.db.DirectStatements;
5 import org.simantics.db.ReadGraph;
6 import org.simantics.db.RelationInfo;
7 import org.simantics.db.Resource;
8 import org.simantics.db.common.procedure.wrapper.NoneToAsyncProcedure;
9 import org.simantics.db.common.procedure.wrapper.SyncToAsyncProcedure;
10 import org.simantics.db.exception.AssumptionException;
11 import org.simantics.db.exception.DatabaseException;
12 import org.simantics.db.impl.ClusterI;
13 import org.simantics.db.impl.ClusterI.ClusterTypeEnum;
14 import org.simantics.db.impl.ForEachObjectContextProcedure;
15 import org.simantics.db.impl.ForEachObjectProcedure;
16 import org.simantics.db.impl.ForPossibleRelatedValueContextProcedure;
17 import org.simantics.db.impl.ForPossibleRelatedValueProcedure;
18 import org.simantics.db.impl.ResourceImpl;
19 import org.simantics.db.impl.TransientGraph;
20 import org.simantics.db.impl.graph.ReadGraphImpl;
21 import org.simantics.db.procedure.AsyncContextMultiProcedure;
22 import org.simantics.db.procedure.AsyncContextProcedure;
23 import org.simantics.db.procedure.AsyncMultiProcedure;
24 import org.simantics.db.procedure.AsyncProcedure;
25 import org.simantics.db.procedure.Procedure;
26 import org.simantics.db.procedure.SyncProcedure;
27 import org.simantics.db.procore.cluster.ClusterBig;
28 import org.simantics.db.procore.cluster.ClusterImpl;
29 import org.simantics.db.procore.cluster.ClusterSmall;
30 import org.simantics.db.procore.cluster.ResourceTableSmall;
31 import org.simantics.db.procore.cluster.ValueTableSmall;
32 import org.simantics.db.request.AsyncRead;
33 import org.simantics.db.service.DirectQuerySupport;
34
35 /**
36  * Note that the direct value retrieval in this implementation only supports
37  * String-type literals - nothing else!
38  * 
39  * This implementation is mainly intended for optimizing database indexing
40  * performance.
41  */
42 public class DirectQuerySupportImpl implements DirectQuerySupport {
43
44         final private SessionImplSocket session;
45         
46         DirectQuerySupportImpl(SessionImplSocket session) {
47                 this.session = session;
48         }
49
50         @Override
51         final public void forEachDirectPersistentStatement(AsyncReadGraph graph, final Resource subject, final AsyncProcedure<DirectStatements> procedure) {
52                 ReadGraphImpl impl = (ReadGraphImpl)graph;
53                 impl.processor.forEachDirectStatement(impl, subject, procedure, true);
54         }
55
56         @Override
57         final public void forEachDirectStatement(AsyncReadGraph graph, final Resource subject, final AsyncProcedure<DirectStatements> procedure) {
58                 ReadGraphImpl impl = (ReadGraphImpl)graph;
59                 impl.processor.forEachDirectStatement(impl, subject, procedure, false);
60         }
61
62         @Override
63         public void forEachDirectStatement(AsyncReadGraph graph, Resource subject, SyncProcedure<DirectStatements> procedure) {
64                 forEachDirectStatement(graph, subject, new SyncToAsyncProcedure<DirectStatements>(procedure));
65         }
66
67         @Override
68         public void forEachDirectStatement(AsyncReadGraph graph, Resource subject, Procedure<DirectStatements> procedure) {
69                 ReadGraphImpl impl = (ReadGraphImpl)graph;
70                 impl.processor.forEachDirectStatement(impl, subject, procedure);
71         }
72
73         @Override
74         public void forRelationInfo(AsyncReadGraph graph, Resource subject, AsyncProcedure<RelationInfo> procedure) {
75                 ReadGraphImpl impl = (ReadGraphImpl)graph;
76                 impl.processor.forRelationInfo(impl, subject, procedure);
77         }
78
79         @Override
80         public void forRelationInfo(AsyncReadGraph graph, Resource subject, SyncProcedure<RelationInfo> procedure) {
81                 forRelationInfo(graph, subject, new SyncToAsyncProcedure<RelationInfo>(procedure));
82         }
83
84         @Override
85         public void forRelationInfo(AsyncReadGraph graph, Resource subject, Procedure<RelationInfo> procedure) {
86                 forRelationInfo(graph, subject, new NoneToAsyncProcedure<RelationInfo>(procedure));
87         }
88
89         @Override
90         public AsyncMultiProcedure<Resource> compileForEachObject(ReadGraph graph, final Resource relation, AsyncMultiProcedure<Resource> user) {
91                 
92                 try {
93                         RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
94
95                                 @Override
96                                 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
97                                         forRelationInfo(graph, relation, procedure);
98                                 }
99
100                 @Override
101                     public int threadHash() {
102                         return hashCode();
103                     }
104
105                                 @Override
106                                 public int getFlags() {
107                                         return 0;
108                                 }
109
110                         });
111                 final int predicateKey = ((ResourceImpl)relation).id;
112                         return new ForEachObjectProcedure(predicateKey, info, session.queryProvider2, user);
113                 } catch (DatabaseException e) {
114                         return null;
115                 }               
116         
117         }
118
119         @Override
120         public <C> AsyncContextMultiProcedure<C, Resource> compileForEachObject(ReadGraph graph, final Resource relation, AsyncContextMultiProcedure<C, Resource> user) {
121                 
122                 try {
123                         RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
124
125                                 @Override
126                                 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
127                                         forRelationInfo(graph, relation, procedure);
128                                 }
129
130                 @Override
131                     public int threadHash() {
132                         return hashCode();
133                     }
134
135                                 @Override
136                                 public int getFlags() {
137                                         return 0;
138                                 }
139
140                         });
141                 final int predicateKey = ((ResourceImpl)relation).id;
142                         return new ForEachObjectContextProcedure<C>(predicateKey, info, session.queryProvider2, user);
143                 } catch (DatabaseException e) {
144                         return null;
145                 }               
146         
147         }
148         
149         @Override
150         public <T> AsyncProcedure<T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, AsyncProcedure<T> user) {
151                 
152                 try {
153                         RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
154
155                                 @Override
156                                 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
157                                         forRelationInfo(graph, relation, procedure);
158                                 }
159
160                 @Override
161                     public int threadHash() {
162                         return hashCode();
163                     }
164
165                                 @Override
166                                 public int getFlags() {
167                                         return 0;
168                                 }
169
170                         });
171                 final int predicateKey = ((ResourceImpl)relation).id;
172                         return new ForPossibleRelatedValueProcedure<T>(predicateKey, info, user);
173                 } catch (DatabaseException e) {
174                         return null;
175                 }               
176         
177         }
178
179         @Override
180         public <C, T> AsyncContextProcedure<C, T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, AsyncContextProcedure<C, T> user) {
181                 
182                 try {
183                         RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
184
185                                 @Override
186                                 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
187                                         forRelationInfo(graph, relation, procedure);
188                                 }
189
190                 @Override
191                     public int threadHash() {
192                         return hashCode();
193                     }
194
195                                 @Override
196                                 public int getFlags() {
197                                         return 0;
198                                 }
199
200                         });
201                 final int predicateKey = ((ResourceImpl)relation).id;
202                         return new ForPossibleRelatedValueContextProcedure<C, T>(predicateKey, info, user);
203                 } catch (DatabaseException e) {
204                         return null;
205                 }               
206         
207         }
208         
209         @Override
210         public void forEachObjectCompiled(AsyncReadGraph graph, Resource subject, final AsyncMultiProcedure<Resource> procedure) {
211                 
212         assert(subject != null);
213         
214         final ForEachObjectProcedure proc = (ForEachObjectProcedure)procedure;
215 //        final RelationInfo info = proc.info;
216
217         final ReadGraphImpl impl = (ReadGraphImpl)graph;
218         final int subjectId = ((ResourceImpl)subject).id;
219
220 //        int callerThread = impl.callerThread;
221 //        int suggestSchedule = (subjectId>>16) & queryProvider2.THREAD_MASK;
222         
223 //        impl.inc();
224         
225 //        if(callerThread == suggestSchedule) {
226                 
227 //              if(info.isFunctional) {
228 //                      querySupport.getObjects4(impl, subjectId, proc);
229 //              } else {
230                 session.querySupport.getObjects4(impl, subjectId, proc);
231 //              }
232                 
233 //        } else {
234 //              
235 //              impl.state.barrier.inc();
236 //            impl.state.barrier.dec(callerThread);
237 //              
238 //              queryProvider2.schedule(callerThread, new SessionTask(suggestSchedule) {
239 //      
240 //                      @Override
241 //                      public void run(int thread) {
242 //                              
243 //                      impl.state.barrier.inc(thread);
244 //                              impl.state.barrier.dec();
245 //
246 //                      if(info.isFunctional) {
247 //                              querySupport.getObjects4(impl.newAsync(thread), subjectId, proc);
248 //                      } else {
249 //                              querySupport.getObjects4(impl.newAsync(thread), subjectId, proc);
250 //                      }
251 //                              
252 //                      }
253 //                      
254 //                      @Override
255 //                      public String toString() {
256 //                              return "gaff8";
257 //                      }
258 //      
259 //              });
260 //              
261 //        }
262                 
263         }
264
265         @Override
266         public <C> void forEachObjectCompiled(AsyncReadGraph graph, Resource subject, C context, final AsyncContextMultiProcedure<C, Resource> procedure) {
267                 
268                 assert(subject != null);
269
270                 final ForEachObjectContextProcedure<C> proc = (ForEachObjectContextProcedure<C>)procedure;
271                 final RelationInfo info = proc.info;
272
273                 final ReadGraphImpl impl = (ReadGraphImpl)graph;
274                 final int subjectId = ((ResourceImpl)subject).id;
275
276 //              int callerThread = impl.callerThread;
277 //              int suggestSchedule = (subjectId>>16) & queryProvider2.THREAD_MASK;
278
279 //              impl.inc();
280
281                 if(info.isFunctional) {
282                         session.querySupport.getObjects4(impl, subjectId, context, proc);
283                 } else {
284                         session.querySupport.getObjects4(impl, subjectId, context, proc);
285                 }
286                 
287         }
288         
289         @Override
290         public <T> void forPossibleRelatedValueCompiled(AsyncReadGraph graph, Resource subject, final AsyncProcedure<T> procedure) {
291                 
292                 assert(subject != null);
293
294         final ForPossibleRelatedValueProcedure<T> proc = (ForPossibleRelatedValueProcedure<T>)procedure;
295         final RelationInfo info = proc.info;
296         
297         final ReadGraphImpl impl = (ReadGraphImpl)graph;
298         final int subjectId = ((ResourceImpl)subject).id;
299         
300 //        int callerThread = impl.callerThread;
301 //        int suggestSchedule = (subjectId>>16) & session.queryProvider2.THREAD_MASK;
302         
303 //        impl.inc();
304         
305 //        if(callerThread == suggestSchedule) {
306                 
307                 if(info.isFunctional) {
308                         getRelatedValue4(impl, subjectId, proc);
309                 } else {
310                         getRelatedValue4(impl, subjectId, proc);
311                 }
312                 
313 //        } else {
314 //              
315 //              impl.state.barrier.inc();
316 //            impl.state.barrier.dec(callerThread);
317 //              
318 //              queryProvider2.schedule(callerThread, new SessionTask(suggestSchedule) {
319 //      
320 //                      @Override
321 //                      public void run(int thread) {
322 //
323 //                      impl.state.barrier.inc(thread);
324 //                      impl.state.barrier.dec();
325 //                              
326 //                      if(info.isFunctional) {
327 //                              getRelatedValue4(impl.newAsync(thread), subjectId, proc);
328 //                      } else {
329 //                              getRelatedValue4(impl.newAsync(thread), subjectId, proc);
330 //                      }
331 //                              
332 //                      }
333 //                      
334 //                      @Override
335 //                      public String toString() {
336 //                              return "gaff11";
337 //                      }
338 //      
339 //              });
340 //              
341 //        }
342                 
343         }
344
345         @Override
346         public <C, T> void forPossibleRelatedValueCompiled(AsyncReadGraph graph, Resource subject, C context, final AsyncContextProcedure<C, T> procedure) {
347                 
348                 assert(subject != null);
349
350         final ForPossibleRelatedValueContextProcedure<C, T> proc = (ForPossibleRelatedValueContextProcedure<C, T>)procedure;
351         final RelationInfo info = proc.info;
352         
353         final ReadGraphImpl impl = (ReadGraphImpl)graph;
354         final int subjectId = ((ResourceImpl)subject).id;
355         
356 //        int callerThread = impl.callerThread;
357 //        int suggestSchedule = (subjectId>>16) & session.queryProvider2.THREAD_MASK;
358         
359 //        impl.inc();
360                 
361         if(info.isFunctional) {
362                 getRelatedValue4(impl, subjectId, context, proc);
363         } else {
364                 getRelatedValue4(impl, subjectId, context, proc);
365         }
366                 
367         }
368         
369         @Override
370         public <T> void forPossibleType(final AsyncReadGraph graph, Resource subject, final AsyncProcedure<Resource> procedure) {
371                 
372         assert(subject != null);
373
374         final ReadGraphImpl impl = (ReadGraphImpl)graph;
375         final int subjectId = ((ResourceImpl)subject).id;
376
377         try {
378                 
379                 final ClusterI cluster = session.clusterTable.getClusterByResourceKey(subjectId);
380                 if(!cluster.isLoaded()) {
381
382 //                      impl.state.inc(0);
383                         
384                         session.queryProvider2.requestCluster(impl, cluster.getClusterId(), new Runnable() {
385                 
386                                         @Override
387                                         public void run() {
388
389                                         try {
390
391                                                         int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
392                                                 procedure.execute(graph, new ResourceImpl(session.resourceSupport, result));
393
394 //                                              impl.state.dec(0);                                              
395                                                 
396                                         } catch (DatabaseException e) {
397                                                 e.printStackTrace();
398                                         }
399                 
400                                         }
401                 
402                                 });
403                                 
404                 } else {
405
406                         int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
407                         procedure.execute(graph, new ResourceImpl(session.resourceSupport, result));
408                         
409                 }
410                 
411         } catch (DatabaseException e) {
412                 e.printStackTrace();
413         }
414         
415         
416                 
417         }
418
419         @Override
420         public <C> void forPossibleDirectType(final AsyncReadGraph graph, Resource subject, final C context, final AsyncContextProcedure<C, Resource> procedure) {
421                 
422         assert(subject != null);
423
424         final ReadGraphImpl impl = (ReadGraphImpl)graph;
425         final int subjectId = ((ResourceImpl)subject).id;
426         
427         try {
428                 
429                 final ClusterI cluster = session.clusterTable.getClusterByResourceKey(subjectId);
430                 if(!cluster.isLoaded()) {
431
432 //                      impl.state.inc(0);
433                         
434                         session.queryProvider2.requestCluster(impl, cluster.getClusterId(), new Runnable() {
435                 
436                                         @Override
437                                         public void run() {
438
439                                         try {
440
441                                                 ClusterI.CompleteTypeEnum type = cluster.getCompleteType(subjectId, session.clusterTranslator);
442                                                 if(ClusterI.CompleteTypeEnum.InstanceOf == type) {
443                                                         int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
444                                                         procedure.execute(graph, context, new ResourceImpl(session.resourceSupport, result));
445                                                 } else {
446                                                 procedure.execute(graph, context, null);
447                                                 }
448
449 //                                              impl.state.dec(0);
450                                                 
451                                         } catch (DatabaseException e) {
452                                                 e.printStackTrace();
453                                         }
454                 
455                                         }
456                 
457                                 });
458                                 
459                 } else {
460
461                         ClusterI.CompleteTypeEnum type = cluster.getCompleteType(subjectId, session.clusterTranslator);
462                         if(ClusterI.CompleteTypeEnum.InstanceOf == type) {
463                                 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
464                                 procedure.execute(graph, context, new ResourceImpl(session.resourceSupport, result));
465                         } else {
466                         procedure.execute(graph, context, null);
467                         }
468                         
469                 }
470                 
471         } catch (DatabaseException e) {
472                 
473                 procedure.execute(graph, context, null);
474                 
475         } catch (Throwable t) {
476
477                 t.printStackTrace();
478                 procedure.execute(graph, context, null);
479                 
480         }
481                 
482         }
483         
484         
485         private <C, T> void getRelatedValue4(final ReadGraphImpl graph, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
486                 
487                 int result = 0;
488                 
489                 final int predicate = procedure.predicateKey;
490
491                 if(subject < 0) {
492
493                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
494                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
495                                     g -> getRelatedValue4(g, subject, context, procedure)
496                                 );
497                                 return;
498                         }
499                         
500                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
501                 for (int id : g.getObjects(subject, predicate)) {
502                         if(result != 0) {
503                                 procedure.exception(graph, new DatabaseException("Multiple objects"));
504 //                              graph.dec();
505                                 return;
506                         } else {
507                                 result = id;
508                         }
509                 }
510                         }
511                         
512                         if(result == 0) {
513                                 
514                         procedure.exception(graph, new DatabaseException("No objects for " + subject ));
515 //                      graph.dec();
516                         return;
517                         
518                         } else {
519                                 
520                                 getValue4(graph, null, result, context, procedure);
521                                 return;
522                                 
523                         }
524                         
525                 } 
526                 
527         final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
528         if(!cluster.isLoaded()) {
529                 cluster.load(session.clusterTranslator, () -> getRelatedValue4(graph, subject, context, procedure));
530                 return;
531         }
532         
533         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
534                         
535                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
536                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
537                                     g -> getRelatedValue4(g, subject, context, procedure)
538                                 );
539                                 return;
540                         }
541                 
542                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
543                 for (int id : g.getObjects(subject, predicate)) {
544                         if(result != 0) {
545                                 procedure.exception(graph, new DatabaseException("Multiple objects"));
546 //                              graph.dec();
547                                 return;
548                         } else {
549                                 result = id;
550                         }
551                 }
552                         }
553                         
554                         getRelatedDirectValue4(graph, cluster, subject, result, context, procedure);
555                         
556                 } else {
557                         
558                         getRelatedDirectValue4(graph, cluster, subject, 0, context, procedure);
559                         
560                 }
561                 
562         }
563         
564         @SuppressWarnings("unchecked")
565         private <T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
566                 
567                 Object result = null;
568         
569                 if(subject < 0) {
570
571                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
572                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, 
573                                     g -> getValue4(g, containerCluster, subject, procedure)
574                             );
575                                 return;
576                         }
577                         
578                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
579                                 Object value = g.getValue(subject);
580                                 if(value != null) {
581                                         if(result != null) {
582                                                 procedure.exception(graph, new DatabaseException("Multiple values"));
583 //                                              graph.dec();
584                                                 return;
585                                         } else {
586                                                 result = value;
587                                         }
588                                 }
589                         }
590
591                         procedure.execute(graph, (T)"name");
592 //                      graph.dec();
593                         return;
594
595                 }
596                 
597                 ClusterImpl cluster = containerCluster;
598                 if(!containerCluster.contains(subject)) {
599                         cluster = session.clusterTable.getClusterByResourceKey(subject);
600                         if(!cluster.isLoaded()) {
601                                 cluster.load(session.clusterTranslator, new Runnable() {
602
603                                         @Override
604                                         public void run() {
605                                                 getValue4(graph, containerCluster, subject, procedure);
606                                         }
607
608                                 });
609                                 return;
610                         }
611                 }
612                 
613         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
614
615                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
616                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
617                             g -> getValue4(g, containerCluster, subject, procedure)
618                             );
619                                 return;
620                         }
621                 
622                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
623                                 Object value = g.getValue(subject);
624                                 if(value != null) {
625                                         if(result != null) {
626                                                 procedure.exception(graph, new DatabaseException("Multiple values"));
627 //                                              graph.dec();
628                                                 return;
629                                         } else {
630                                                 result = value;
631                                         }
632                                 }
633                         }
634                         
635                         if(result != null) {
636                                 
637                                 procedure.execute(graph, (T)result);
638 //                              graph.state.barrier.dec();
639                                 
640                         } else {
641                                 
642                                 if(ClusterTypeEnum.SMALL == cluster.getType())
643                                         getDirectValue4(graph, (ClusterSmall)cluster, subject, procedure);
644                                 else 
645                                         getDirectValue4(graph, (ClusterBig)cluster, subject, procedure);
646                         }
647
648                 } else {
649
650                         if(ClusterTypeEnum.SMALL == cluster.getType())
651                                 getDirectValue4(graph, (ClusterSmall)cluster, subject, procedure);
652                         else 
653                                 getDirectValue4(graph, (ClusterBig)cluster, subject, procedure);
654
655                 }
656         
657         }
658         
659         @SuppressWarnings("unchecked")
660         private <C, T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
661                 
662                 Object result = null;
663         
664                 if(subject < 0) {
665
666                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
667                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
668                                     g -> getValue4(g, containerCluster, subject, context, procedure)
669                             );
670                                 return;
671                         }
672                         
673                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
674                                 Object value = g.getValue(subject);
675                                 if(value != null) {
676                                         if(result != null) {
677                                                 procedure.exception(graph, new DatabaseException("Multiple values"));
678 //                                              graph.dec();
679                                                 return;
680                                         } else {
681                                                 result = value;
682                                         }
683                                 }
684                         }
685
686                         procedure.execute(graph, context, (T)"name");
687 //                      graph.dec();
688                         return;
689
690                 }
691                 
692                 ClusterImpl cluster = containerCluster;
693                 if(!containerCluster.contains(subject)) {
694                         cluster = session.clusterTable.getClusterByResourceKey(subject);
695                         if(!cluster.isLoaded()) {
696                                 cluster.load(session.clusterTranslator, new Runnable() {
697
698                                         @Override
699                                         public void run() {
700                                                 getValue4(graph, containerCluster, subject, context, procedure);
701                                         }
702
703                                 });
704                                 return;
705                         }
706                 }
707                 
708         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
709
710                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
711                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
712                                      g -> getValue4(g, containerCluster, subject, context, procedure)
713                             );
714                                 return;
715                         }
716                 
717                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
718                                 Object value = g.getValue(subject);
719                                 if(value != null) {
720                                         if(result != null) {
721                                                 procedure.exception(graph, new DatabaseException("Multiple values"));
722 //                                              graph.dec();
723                                                 return;
724                                         } else {
725                                                 result = value;
726                                         }
727                                 }
728                         }
729                         
730                         if(result != null) {
731                                 
732                                 procedure.execute(graph, context, (T)result);
733 //                              graph.state.barrier.dec();
734                                 
735                         } else {
736                                 
737                                 if(ClusterTypeEnum.SMALL == cluster.getType())
738                                         getDirectValue4(graph, (ClusterSmall)cluster, subject, context, procedure);
739                                 else 
740                                         getDirectValue4(graph, (ClusterBig)cluster, subject, context, procedure);
741                         }
742
743                 } else {
744
745                         if(ClusterTypeEnum.SMALL == cluster.getType())
746                                 getDirectValue4(graph, (ClusterSmall)cluster, subject, context, procedure);
747                         else 
748                                 getDirectValue4(graph, (ClusterBig)cluster, subject, context, procedure);
749
750                 }
751         
752         }
753
754         private <T> void getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final ForPossibleRelatedValueProcedure<T> procedure) {
755
756                 try {
757
758                         int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
759                         if(so == 0) {
760                                 if(result == 0) {
761                                         procedure.exception(graph, new DatabaseException("No objects " + subject + " " + procedure.predicateKey));
762 //                                      graph.dec();
763                                 } else {
764                                         getValue4(graph, cluster, result, procedure);
765                                 }
766                         } else {
767                                 if(result == 0) {
768                                         getValue4(graph, cluster, so, procedure);
769                                 } else {
770                                         procedure.exception(graph, new DatabaseException("Multiple objects"));
771 //                                      graph.dec();
772                                 }
773                         }
774
775                 } catch (DatabaseException e) {
776                         e.printStackTrace();
777                 }
778                 
779         }
780
781         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) {
782
783                 try {
784
785                         int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
786                         if(so == 0) {
787                                 if(result == 0) {
788                                         procedure.exception(graph, new DatabaseException("No objects " + subject + " " + procedure.predicateKey));
789 //                                      graph.dec();
790                                 } else {
791                                         getValue4(graph, cluster, result, context, procedure);
792                                 }
793                         } else {
794                                 if(result == 0) {
795                                         getValue4(graph, cluster, so, context, procedure);
796                                 } else {
797                                         procedure.exception(graph, new DatabaseException("Multiple objects"));
798 //                                      graph.dec();
799                                 }
800                         }
801
802                 } catch (DatabaseException e) {
803                         e.printStackTrace();
804                 }
805                 
806         }
807         
808         public <T> void getRelatedValue4(final ReadGraphImpl graph, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
809                 
810                 int result = 0;
811                 
812                 final int predicate = procedure.predicateKey;
813
814                 if(subject < 0) {
815
816                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
817                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
818                                     g -> getRelatedValue4(g, subject, procedure)
819                             );
820                                 return;
821                         }
822                         
823                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
824                 for (int id : g.getObjects(subject, predicate)) {
825                         if(result != 0) {
826                                 procedure.exception(graph, new DatabaseException("Multiple objects"));
827 //                              graph.dec();
828                                 return;
829                         } else {
830                                 result = id;
831                         }
832                 }
833                         }
834                         
835                         if(result == 0) {
836                                 
837                         procedure.exception(graph, new DatabaseException("No objects for " + subject ));
838 //                      graph.dec();
839                         return;
840                         
841                         } else {
842                                 
843                                 getValue4(graph, null, result, procedure);
844                                 return;
845                                 
846                         }
847                         
848                 } 
849                 
850         final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
851         if(!cluster.isLoaded()) {
852                 cluster.load(session.clusterTranslator, new Runnable() {
853
854                                 @Override
855                                 public void run() {
856                                         getRelatedValue4(graph, subject, procedure);
857                                 }
858                         
859                 });
860                 return;
861         }
862         
863         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
864                         
865                         if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
866                             SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
867                                     g -> getRelatedValue4(graph, subject, procedure)
868                             );
869                                 return;
870                         }
871                 
872                         for(TransientGraph g : session.virtualGraphServerSupport.providers) {
873                 for (int id : g.getObjects(subject, predicate)) {
874                         if(result != 0) {
875                                 procedure.exception(graph, new DatabaseException("Multiple objects"));
876 //                              graph.dec();
877                                 return;
878                         } else {
879                                 result = id;
880                         }
881                 }
882                         }
883                         
884                         getRelatedDirectValue4(graph, cluster, subject, result, procedure);
885                         
886                 } else {
887                         
888                         getRelatedDirectValue4(graph, cluster, subject, 0, procedure);
889                         
890                 }
891                 
892         }
893         
894         private <C, T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
895                 
896                 try {
897                         byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
898                         @SuppressWarnings("unchecked")
899                         T value = (T)utf(bytes, 0);
900                         procedure.execute(graph, context, value);
901                 } catch (DatabaseException e) {
902                         procedure.execute(graph, context, null);
903                 }
904
905 //              graph.dec();
906                 
907         }
908
909         private <T> void getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
910                 
911                 try {
912                         byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
913                         @SuppressWarnings("unchecked")
914                         T value = (T)utf(bytes, 0);
915                         procedure.execute(graph, value);
916                 } catch (DatabaseException e) {
917                         procedure.execute(graph, null);
918                 }
919
920 //              graph.dec();
921                 
922         }
923
924         private <C, T> void getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
925                 
926                 try {
927                         byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
928                         if(bytes == null) {
929                                 procedure.execute(graph, context, null);
930                         } else {
931                                 @SuppressWarnings("unchecked")
932                                 T value = (T)utf(bytes, 0);
933                                 procedure.execute(graph, context, value);
934                         }
935                 } catch (DatabaseException e) {
936                         procedure.execute(graph, context, null);
937                 }
938
939 //              graph.dec();
940                 
941         }
942         
943         private <T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
944                 try {
945                         // Note: this code avoids creating an intermediate byte[]
946                         // to store the encoded string bytes and reads the UTF string
947                         // from the value table byte[] directly into String instead.
948
949                         ResourceTableSmall rt = cluster.resourceTable;
950                         ValueTableSmall vt = cluster.valueTable;
951
952                         byte[] bs = vt.table;
953                         long[] ls = rt.table;
954
955                         int index = ((subject&0xFFF) << 1) - 1 + rt.offset;
956                         int valueIndex = ((int)(ls[index] >>> 24) & 0x3FFFFF) + vt.offset;
957
958                         int size = bs[valueIndex++];
959                         if (size < 0) // two byte size
960                                 size = (int)(((size & 0x7F) << 8) | (bs[valueIndex++] & 0xFF));
961                         if (size <= 0)
962                                 throw new DatabaseException("No value for " + subject); 
963
964                         @SuppressWarnings("unchecked")
965                         T t = (T) utf(bs, valueIndex);
966
967                         procedure.execute(graph, t);
968                 } catch (DatabaseException e) {
969                         procedure.exception(graph, e);
970                 }
971         }
972
973         final private String utf(byte[] bytes, int offset) throws AssumptionException {
974
975                 if(bytes == null) return null;
976
977                 // Read databoard int32 using Length encoding
978                 // https://dev.simantics.org/index.php/Databoard_Specification#Length
979                 int index = offset;
980                 int length = bytes[index++]&0xff; 
981                 if(length >= 0x80) {
982                         if(length >= 0xc0) {
983                                 if(length >= 0xe0) {
984                                         if(length >= 0xf0) {
985                                                 length &= 0x0f;
986                                                 length += ((bytes[index++]&0xff)<<3);
987                                                 length += ((bytes[index++]&0xff)<<11);
988                                                 length += ((bytes[index++]&0xff)<<19);
989                                                 length += 0x10204080;
990                                         }
991                                         else {
992                                                 length &= 0x1f;
993                                                 length += ((bytes[index++]&0xff)<<4);
994                                                 length += ((bytes[index++]&0xff)<<12);
995                                                 length += ((bytes[index++]&0xff)<<20);
996                                                 length += 0x204080;
997                                         }
998                                 }
999                                 else {
1000                                         length &= 0x3f;
1001                                         length += ((bytes[index++]&0xff)<<5);
1002                                         length += ((bytes[index++]&0xff)<<13);
1003                                         length += 0x4080;
1004                                 }
1005                         }
1006                         else {
1007                                 length &= 0x7f;
1008                                 length += ((bytes[index++]&0xff)<<6);
1009                                 length += 0x80;
1010                         }
1011                 }
1012
1013                 // Copied from DataInputStream
1014                 int utflen = length;
1015                 char[] chararr = new char[utflen];
1016
1017                 int c, char2, char3;
1018                 int count = index;
1019                 int target = index + length;
1020                 int chararr_count=0;
1021
1022                 while (count < target) {
1023                         c = (int) bytes[count] & 0xff;
1024                         if (c > 127) break;
1025                         count++;
1026                         chararr[chararr_count++]=(char)c;
1027                 }
1028
1029                 while (count < target) {
1030                         c = (int) bytes[count] & 0xff;
1031                         switch (c >> 4) {
1032                         case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
1033                                 /* 0xxxxxxx*/
1034                                 count++;
1035                                 chararr[chararr_count++]=(char)c;
1036                                 break;
1037                         case 12: case 13:
1038                                 /* 110x xxxx   10xx xxxx*/
1039                                 count += 2;
1040                                 if (count > target)
1041                                         throw new AssumptionException(
1042                                                         "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
1043                                 char2 = (int) bytes[count-1];
1044                                 if ((char2 & 0xC0) != 0x80)
1045                                         throw new AssumptionException(
1046                                                         "malformed input around byte " + count); 
1047                                 chararr[chararr_count++]=(char)(((c & 0x1F) << 6) | 
1048                                                 (char2 & 0x3F));  
1049                                 break;
1050                         case 14:
1051                                 /* 1110 xxxx  10xx xxxx  10xx xxxx */
1052                                 count += 3;
1053                                 if (count > target)
1054                                         throw new AssumptionException(
1055                                                         "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
1056                                 char2 = (int) bytes[count-2];
1057                                 char3 = (int) bytes[count-1];
1058                                 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
1059                                         throw new AssumptionException(
1060                                                         "malformed input around byte " + (count-1));
1061                                 chararr[chararr_count++]=(char)(((c     & 0x0F) << 12) |
1062                                                 ((char2 & 0x3F) << 6)  |
1063                                                 ((char3 & 0x3F) << 0));
1064                                 break;
1065                         default:
1066                                 /* 10xx xxxx,  1111 xxxx */
1067                                 throw new AssumptionException(
1068                                                 "malformed input around byte " + count);
1069                         }
1070                 }
1071
1072                 // The number of chars produced may be less than utflen
1073                 return new String(chararr, 0, chararr_count);
1074         }
1075
1076 }