1 package fi.vtt.simantics.procore.internal;
3 import org.simantics.db.DirectStatements;
4 import org.simantics.db.ReadGraph;
5 import org.simantics.db.RelationInfo;
6 import org.simantics.db.Resource;
7 import org.simantics.db.exception.AssumptionException;
8 import org.simantics.db.exception.DatabaseException;
9 import org.simantics.db.exception.NoSingleResultException;
10 import org.simantics.db.impl.ClusterI;
11 import org.simantics.db.impl.ClusterI.ClusterTypeEnum;
12 import org.simantics.db.impl.ForEachObjectContextProcedure;
13 import org.simantics.db.impl.ForEachObjectProcedure;
14 import org.simantics.db.impl.ForPossibleRelatedValueContextProcedure;
15 import org.simantics.db.impl.ForPossibleRelatedValueProcedure;
16 import org.simantics.db.impl.ResourceImpl;
17 import org.simantics.db.impl.TransientGraph;
18 import org.simantics.db.impl.graph.ReadGraphImpl;
19 import org.simantics.db.procedure.SyncContextMultiProcedure;
20 import org.simantics.db.procedure.SyncContextProcedure;
21 import org.simantics.db.procedure.SyncMultiProcedure;
22 import org.simantics.db.procedure.SyncProcedure;
23 import org.simantics.db.procore.cluster.ClusterBig;
24 import org.simantics.db.procore.cluster.ClusterImpl;
25 import org.simantics.db.procore.cluster.ClusterSmall;
26 import org.simantics.db.procore.cluster.ResourceTableSmall;
27 import org.simantics.db.procore.cluster.ValueTableSmall;
28 import org.simantics.db.service.DirectQuerySupport;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 public class DirectQuerySupportImpl implements DirectQuerySupport {
34 private static final Logger LOGGER = LoggerFactory.getLogger(DirectQuerySupportImpl.class);
36 final private SessionImplSocket session;
38 DirectQuerySupportImpl(SessionImplSocket session) {
39 this.session = session;
43 final public DirectStatements getDirectPersistentStatements(ReadGraph graph, final Resource subject) {
44 ReadGraphImpl impl = (ReadGraphImpl)graph;
45 return impl.processor.getDirectStatements(impl, subject, true);
49 final public DirectStatements getDirectStatements(ReadGraph graph, final Resource subject) {
50 ReadGraphImpl impl = (ReadGraphImpl)graph;
51 return impl.processor.getDirectStatements(impl, subject, false);
55 public RelationInfo getRelationInfo(ReadGraph graph, Resource subject) throws DatabaseException {
56 ReadGraphImpl impl = (ReadGraphImpl)graph;
57 return impl.processor.getRelationInfo(impl, subject);
61 public SyncMultiProcedure<Resource> compileForEachObject(ReadGraph graph, final Resource relation, SyncMultiProcedure<Resource> user) throws DatabaseException {
63 RelationInfo info = getRelationInfo(graph, relation);
64 final int predicateKey = ((ResourceImpl)relation).id;
65 return new ForEachObjectProcedure(predicateKey, info, session.queryProvider2, user);
70 public <C> SyncContextMultiProcedure<C, Resource> compileForEachObject(ReadGraph graph, final Resource relation, SyncContextMultiProcedure<C, Resource> user) throws DatabaseException {
72 RelationInfo info = getRelationInfo(graph, relation);
73 final int predicateKey = ((ResourceImpl)relation).id;
74 return new ForEachObjectContextProcedure<C>(predicateKey, info, session.queryProvider2, user);
79 public <T> SyncProcedure<T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, SyncProcedure<T> user) throws DatabaseException {
81 RelationInfo info = getRelationInfo(graph, relation);
82 final int predicateKey = ((ResourceImpl)relation).id;
83 return new ForPossibleRelatedValueProcedure<T>(predicateKey, info, user);
88 public <C, T> SyncContextProcedure<C, T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, SyncContextProcedure<C, T> user) throws DatabaseException {
90 RelationInfo info = getRelationInfo(graph, relation);
91 final int predicateKey = ((ResourceImpl)relation).id;
92 return new ForPossibleRelatedValueContextProcedure<C, T>(predicateKey, info, user);
97 public void forEachObjectCompiled(ReadGraph graph, Resource subject, final SyncMultiProcedure<Resource> procedure) {
99 assert(subject != null);
101 final ForEachObjectProcedure proc = (ForEachObjectProcedure)procedure;
102 // final RelationInfo info = proc.info;
104 final ReadGraphImpl impl = (ReadGraphImpl)graph;
105 final int subjectId = ((ResourceImpl)subject).id;
107 // int callerThread = impl.callerThread;
108 // int suggestSchedule = (subjectId>>16) & queryProvider2.THREAD_MASK;
112 // if(callerThread == suggestSchedule) {
114 // if(info.isFunctional) {
115 // querySupport.getObjects4(impl, subjectId, proc);
117 session.querySupport.getObjects4(impl, subjectId, proc);
122 // impl.state.barrier.inc();
123 // impl.state.barrier.dec(callerThread);
125 // queryProvider2.schedule(callerThread, new SessionTask(suggestSchedule) {
128 // public void run(int thread) {
130 // impl.state.barrier.inc(thread);
131 // impl.state.barrier.dec();
133 // if(info.isFunctional) {
134 // querySupport.getObjects4(impl.newAsync(thread), subjectId, proc);
136 // querySupport.getObjects4(impl.newAsync(thread), subjectId, proc);
142 // public String toString() {
153 public <C> void forEachObjectCompiled(ReadGraph graph, Resource subject, C context, final SyncContextMultiProcedure<C, Resource> procedure) {
155 assert(subject != null);
157 final ForEachObjectContextProcedure<C> proc = (ForEachObjectContextProcedure<C>)procedure;
158 final RelationInfo info = proc.info;
160 final ReadGraphImpl impl = (ReadGraphImpl)graph;
161 final int subjectId = ((ResourceImpl)subject).id;
163 // int callerThread = impl.callerThread;
164 // int suggestSchedule = (subjectId>>16) & queryProvider2.THREAD_MASK;
168 if(info.isFunctional) {
169 session.querySupport.getObjects4(impl, subjectId, context, proc);
171 session.querySupport.getObjects4(impl, subjectId, context, proc);
177 public <T> void forPossibleRelatedValueCompiled(ReadGraph graph, Resource subject, final SyncProcedure<T> procedure) {
179 assert(subject != null);
181 final ForPossibleRelatedValueProcedure<T> proc = (ForPossibleRelatedValueProcedure<T>)procedure;
182 final RelationInfo info = proc.info;
184 final ReadGraphImpl impl = (ReadGraphImpl)graph;
185 final int subjectId = ((ResourceImpl)subject).id;
187 // int callerThread = impl.callerThread;
188 // int suggestSchedule = (subjectId>>16) & session.queryProvider2.THREAD_MASK;
192 // if(callerThread == suggestSchedule) {
194 // if(info.isFunctional) {
196 T result = getRelatedValue4(impl, subjectId, proc);
198 proc.execute(graph, result);
199 } catch (DatabaseException e2) {
200 LOGGER.error("Unexpected exception while handling related value", e2);
202 } catch (DatabaseException e) {
204 proc.exception(graph, e);
205 } catch (DatabaseException e2) {
206 LOGGER.error("Unexpected exception while handling related value", e2);
210 // getRelatedValue4(impl, subjectId, proc);
215 // impl.state.barrier.inc();
216 // impl.state.barrier.dec(callerThread);
218 // queryProvider2.schedule(callerThread, new SessionTask(suggestSchedule) {
221 // public void run(int thread) {
223 // impl.state.barrier.inc(thread);
224 // impl.state.barrier.dec();
226 // if(info.isFunctional) {
227 // getRelatedValue4(impl.newAsync(thread), subjectId, proc);
229 // getRelatedValue4(impl.newAsync(thread), subjectId, proc);
235 // public String toString() {
246 public <C, T> void forPossibleRelatedValueCompiled(ReadGraph graph, Resource subject, C context, final SyncContextProcedure<C, T> procedure) {
248 assert(subject != null);
250 final ForPossibleRelatedValueContextProcedure<C, T> proc = (ForPossibleRelatedValueContextProcedure<C, T>)procedure;
251 final RelationInfo info = proc.info;
253 final ReadGraphImpl impl = (ReadGraphImpl)graph;
254 final int subjectId = ((ResourceImpl)subject).id;
256 // int callerThread = impl.callerThread;
257 // int suggestSchedule = (subjectId>>16) & session.queryProvider2.THREAD_MASK;
261 // if(info.isFunctional) {
263 // getRelatedValue4(impl, subjectId, context, proc);
267 T result = getRelatedValue4(impl, subjectId, context, proc);
268 proc.execute(graph, context, result);
269 } catch (DatabaseException e) {
270 proc.execute(graph, context, null);
276 public <T> void forPossibleType(final AsyncReadGraph graph, Resource subject, final AsyncProcedure<Resource> procedure) {
278 assert(subject != null);
280 final ReadGraphImpl impl = (ReadGraphImpl)graph;
281 final int subjectId = ((ResourceImpl)subject).id;
285 final ClusterI cluster = session.clusterTable.getClusterByResourceKey(subjectId);
286 if(!cluster.isLoaded()) {
288 // impl.state.inc(0);
290 session.queryProvider2.requestCluster(impl, cluster.getClusterId(), new Runnable() {
297 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
298 procedure.execute(graph, new ResourceImpl(session.resourceSupport, result));
300 // impl.state.dec(0);
302 } catch (DatabaseException e) {
312 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
313 procedure.execute(graph, new ResourceImpl(session.resourceSupport, result));
317 } catch (DatabaseException e) {
328 public <C> void forPossibleDirectType(final ReadGraph graph, Resource subject, final C context, final SyncContextProcedure<C, Resource> procedure) {
330 assert(subject != null);
332 final ReadGraphImpl impl = (ReadGraphImpl)graph;
333 final int subjectId = ((ResourceImpl)subject).id;
337 final ClusterI cluster = session.clusterTable.getClusterByResourceKey(subjectId);
338 if(!cluster.isLoaded()) {
340 // impl.state.inc(0);
342 session.queryProvider2.requestCluster(impl, cluster.getClusterId(), new Runnable() {
349 ClusterI.CompleteTypeEnum type = cluster.getCompleteType(subjectId, session.clusterTranslator);
350 if(ClusterI.CompleteTypeEnum.InstanceOf == type) {
351 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
352 procedure.execute(graph, context, new ResourceImpl(session.resourceSupport, result));
354 procedure.execute(graph, context, null);
357 // impl.state.dec(0);
359 } catch (DatabaseException e) {
360 LOGGER.error("forPossibleDirectType requestCluster callback failed", e);
369 ClusterI.CompleteTypeEnum type = cluster.getCompleteType(subjectId, session.clusterTranslator);
370 if(ClusterI.CompleteTypeEnum.InstanceOf == type) {
371 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
372 procedure.execute(graph, context, new ResourceImpl(session.resourceSupport, result));
374 procedure.execute(graph, context, null);
379 } catch (DatabaseException e) {
381 procedure.execute(graph, context, null);
383 } catch (Throwable t) {
385 LOGGER.error("forPossibleDirectType failed unexpectedly", t);
386 procedure.execute(graph, context, null);
392 private <C, T> T getRelatedValue4(final ReadGraphImpl graph, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) throws DatabaseException {
396 final int predicate = procedure.predicateKey;
400 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
401 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
402 return getRelatedValue4(graph, subject, context, procedure);
405 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
406 for (int id : g.getObjects(subject, predicate)) {
408 throw new DatabaseException("Multiple objects");
416 throw new DatabaseException("No objects for " + subject );
418 return getValue4(graph, null, result, context, procedure);
423 final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
424 if(!cluster.isLoaded()) {
426 return getRelatedValue4(graph, subject, context, procedure);
429 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
431 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
432 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
433 return getRelatedValue4(graph, subject, context, procedure);
436 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
437 for (int id : g.getObjects(subject, predicate)) {
439 throw new DatabaseException("Multiple objects");
446 return getRelatedDirectValue4(graph, cluster, subject, result, context, procedure);
450 return getRelatedDirectValue4(graph, cluster, subject, 0, context, procedure);
456 private <T> T getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) throws DatabaseException {
458 Object result = null;
462 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
463 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
464 return getValue4(graph, containerCluster, subject, procedure);
467 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
468 Object value = g.getValue(subject);
471 throw new DatabaseException("Multiple values");
482 ClusterImpl cluster = containerCluster;
483 if(!containerCluster.contains(subject)) {
484 cluster = session.clusterTable.getClusterByResourceKey(subject);
485 if(!cluster.isLoaded()) {
487 return getValue4(graph, containerCluster, subject, procedure);
491 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
493 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
494 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
495 return getValue4(graph, containerCluster, subject, procedure);
498 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
499 Object value = g.getValue(subject);
502 throw new DatabaseException("Multiple values");
512 if(ClusterTypeEnum.SMALL == cluster.getType())
513 return getDirectValue4(graph, (ClusterSmall)cluster, subject);
515 return getDirectValue4(graph, (ClusterBig)cluster, subject);
520 if(ClusterTypeEnum.SMALL == cluster.getType())
521 return getDirectValue4(graph, (ClusterSmall)cluster, subject);
523 return getDirectValue4(graph, (ClusterBig)cluster, subject);
529 private <C, T> T getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) throws DatabaseException {
531 Object result = null;
535 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
536 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
537 return getValue4(graph, containerCluster, subject, context, procedure);
540 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
541 Object value = g.getValue(subject);
544 throw new DatabaseException("Multiple values");
555 ClusterImpl cluster = containerCluster;
556 if(!containerCluster.contains(subject)) {
557 cluster = session.clusterTable.getClusterByResourceKey(subject);
558 if(!cluster.isLoaded()) {
560 return getValue4(graph, containerCluster, subject, context, procedure);
564 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
566 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
567 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, g -> {});
568 return getValue4(graph, containerCluster, subject, context, procedure);
571 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
572 Object value = g.getValue(subject);
575 throw new DatabaseException("Multiple values");
585 if(ClusterTypeEnum.SMALL == cluster.getType())
586 return getDirectValue4(graph, (ClusterSmall)cluster, subject);
588 return getDirectValue4(graph, (ClusterBig)cluster, subject);
593 if(ClusterTypeEnum.SMALL == cluster.getType())
594 return getDirectValue4(graph, (ClusterSmall)cluster, subject);
596 return getDirectValue4(graph, (ClusterBig)cluster, subject);
602 private <T> T getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final ForPossibleRelatedValueProcedure<T> procedure) throws DatabaseException {
604 int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
607 throw new DatabaseException("No objects " + subject + " " + procedure.predicateKey);
609 return getValue4(graph, cluster, result, procedure);
613 return getValue4(graph, cluster, so, procedure);
615 throw new DatabaseException("Multiple objects");
621 private <C, T> T getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) throws DatabaseException {
623 int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
626 throw new NoSingleResultException("No objects " + subject + " " + procedure.predicateKey, result);
628 return getValue4(graph, cluster, result, context, procedure);
632 return getValue4(graph, cluster, so, context, procedure);
634 throw new NoSingleResultException("Multiple objects for " + subject + " " + procedure.predicateKey, result);
640 public <T> T getRelatedValue4(final ReadGraphImpl graph, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) throws DatabaseException {
644 final int predicate = procedure.predicateKey;
648 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
649 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
650 return getRelatedValue4(graph, subject, procedure);
653 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
654 for (int id : g.getObjects(subject, predicate)) {
656 throw new DatabaseException("Multiple objects");
664 throw new DatabaseException("No objects for " + subject );
666 return getValue4(graph, null, result, procedure);
671 final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
672 if(!cluster.isLoaded()) {
674 return getRelatedValue4(graph, subject, procedure);
677 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
679 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
680 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, g -> {});
681 return getRelatedValue4(graph, subject, procedure);
684 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
685 for (int id : g.getObjects(subject, predicate)) {
687 throw new DatabaseException("Multiple objects");
694 return getRelatedDirectValue4(graph, cluster, subject, result, procedure);
698 return getRelatedDirectValue4(graph, cluster, subject, 0, procedure);
705 private <C, T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
708 byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
709 T value = (T)utf(bytes);
710 procedure.execute(graph, context, value);
711 } catch (DatabaseException e) {
712 procedure.execute(graph, context, null);
720 private <T> T getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject) throws DatabaseException {
722 byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
723 return (T)utf(bytes);
727 private <T> T getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject) throws DatabaseException {
729 ResourceTableSmall rt = cluster.resourceTable;
730 ValueTableSmall vt = cluster.valueTable;
732 byte[] bs = vt.table;
733 long[] ls = rt.table;
735 int index = ((subject&0xFFF) << 1) - 1 + rt.offset;
737 int valueIndex = (int)(ls[index] >>> 24) & 0x3FFFFF + vt.offset;
739 int size = (int)bs[valueIndex++]-1;
741 throw new DatabaseException("No value for " + subject);
744 char[] chars = new char[size];
746 for(int i=0;i<size;i++) {
747 chars[i] = (char)bs[valueIndex++];
750 return (T)new String(chars);
754 private final String utf(byte[] bytes) throws AssumptionException {
756 if(bytes == null) return null;
758 // Read databoard int32 using Length encoding
759 // https://dev.simantics.org/index.php/Databoard_Specification#Length
761 int length = bytes[index++]&0xff;
767 length += ((bytes[index++]&0xff)<<3);
768 length += ((bytes[index++]&0xff)<<11);
769 length += ((bytes[index++]&0xff)<<19);
770 length += 0x10204080;
774 length += ((bytes[index++]&0xff)<<4);
775 length += ((bytes[index++]&0xff)<<12);
776 length += ((bytes[index++]&0xff)<<20);
782 length += ((bytes[index++]&0xff)<<5);
783 length += ((bytes[index++]&0xff)<<13);
789 length += ((bytes[index++]&0xff)<<6);
794 // Copied from DataInputStream
796 char[] chararr = new char[utflen];
800 int target = index + length;
803 while (count < target) {
804 c = (int) bytes[count] & 0xff;
807 chararr[chararr_count++]=(char)c;
810 while (count < target) {
811 c = (int) bytes[count] & 0xff;
813 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
816 chararr[chararr_count++]=(char)c;
819 /* 110x xxxx 10xx xxxx*/
822 throw new AssumptionException(
823 "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
824 char2 = (int) bytes[count-1];
825 if ((char2 & 0xC0) != 0x80)
826 throw new AssumptionException(
827 "malformed input around byte " + count);
828 chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
832 /* 1110 xxxx 10xx xxxx 10xx xxxx */
835 throw new AssumptionException(
836 "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
837 char2 = (int) bytes[count-2];
838 char3 = (int) bytes[count-1];
839 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
840 throw new AssumptionException(
841 "malformed input around byte " + (count-1));
842 chararr[chararr_count++]=(char)(((c & 0x0F) << 12) |
843 ((char2 & 0x3F) << 6) |
844 ((char3 & 0x3F) << 0));
847 /* 10xx xxxx, 1111 xxxx */
848 throw new AssumptionException(
849 "malformed input around byte " + count);
853 // The number of chars produced may be less than utflen
854 return new String(chararr, 0, chararr_count);