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