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