1 package fi.vtt.simantics.procore.internal;
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;
39 * Note that the direct value retrieval in this implementation only supports
40 * String-type literals - nothing else!
42 * This implementation is mainly intended for optimizing database indexing
45 public class DirectQuerySupportImpl implements DirectQuerySupport {
47 private static final Logger LOGGER = LoggerFactory.getLogger(DirectQuerySupportImpl.class);
49 final private SessionImplSocket session;
51 DirectQuerySupportImpl(SessionImplSocket session) {
52 this.session = session;
56 final public void forEachDirectPersistentStatement(AsyncReadGraph graph, final Resource subject, final AsyncProcedure<DirectStatements> procedure) {
57 ReadGraphImpl impl = (ReadGraphImpl)graph;
58 impl.processor.forEachDirectStatement(impl, subject, procedure, true);
62 final public void forEachDirectStatement(AsyncReadGraph graph, final Resource subject, final AsyncProcedure<DirectStatements> procedure) {
63 ReadGraphImpl impl = (ReadGraphImpl)graph;
64 impl.processor.forEachDirectStatement(impl, subject, procedure, false);
68 public void forEachDirectStatement(AsyncReadGraph graph, Resource subject, SyncProcedure<DirectStatements> procedure) {
69 forEachDirectStatement(graph, subject, new SyncToAsyncProcedure<DirectStatements>(procedure));
73 public void forEachDirectStatement(AsyncReadGraph graph, Resource subject, Procedure<DirectStatements> procedure) {
74 ReadGraphImpl impl = (ReadGraphImpl)graph;
75 impl.processor.forEachDirectStatement(impl, subject, procedure);
79 public void forRelationInfo(AsyncReadGraph graph, Resource subject, AsyncProcedure<RelationInfo> procedure) {
80 ReadGraphImpl impl = (ReadGraphImpl)graph;
81 impl.processor.forRelationInfo(impl, subject, procedure);
85 public void forRelationInfo(AsyncReadGraph graph, Resource subject, SyncProcedure<RelationInfo> procedure) {
86 forRelationInfo(graph, subject, new SyncToAsyncProcedure<RelationInfo>(procedure));
90 public void forRelationInfo(AsyncReadGraph graph, Resource subject, Procedure<RelationInfo> procedure) {
91 forRelationInfo(graph, subject, new NoneToAsyncProcedure<RelationInfo>(procedure));
95 public AsyncMultiProcedure<Resource> compileForEachObject(ReadGraph graph, final Resource relation, AsyncMultiProcedure<Resource> user) {
98 RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
101 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
102 forRelationInfo(graph, relation, procedure);
106 public int threadHash() {
111 public int getFlags() {
116 final int predicateKey = ((ResourceImpl)relation).id;
117 return new ForEachObjectProcedure(predicateKey, info, session.queryProvider2, user);
118 } catch (DatabaseException e) {
125 public <C> AsyncContextMultiProcedure<C, Resource> compileForEachObject(ReadGraph graph, final Resource relation, AsyncContextMultiProcedure<C, Resource> user) {
128 RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
131 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
132 forRelationInfo(graph, relation, procedure);
136 public int threadHash() {
141 public int getFlags() {
146 final int predicateKey = ((ResourceImpl)relation).id;
147 return new ForEachObjectContextProcedure<C>(predicateKey, info, session.queryProvider2, user);
148 } catch (DatabaseException e) {
155 public <T> AsyncProcedure<T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, AsyncProcedure<T> user) {
158 RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
161 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
162 forRelationInfo(graph, relation, procedure);
166 public int threadHash() {
171 public int getFlags() {
176 final int predicateKey = ((ResourceImpl)relation).id;
177 return new ForPossibleRelatedValueProcedure<T>(predicateKey, info, user);
178 } catch (DatabaseException e) {
185 public <C, T> AsyncContextProcedure<C, T> compilePossibleRelatedValue(ReadGraph graph, final Resource relation, AsyncContextProcedure<C, T> user) {
188 RelationInfo info = graph.syncRequest(new AsyncRead<RelationInfo>() {
191 public void perform(AsyncReadGraph graph, AsyncProcedure<RelationInfo> procedure) {
192 forRelationInfo(graph, relation, procedure);
196 public int threadHash() {
201 public int getFlags() {
206 final int predicateKey = ((ResourceImpl)relation).id;
207 return new ForPossibleRelatedValueContextProcedure<C, T>(predicateKey, info, user);
208 } catch (DatabaseException e) {
215 public void forEachObjectCompiled(AsyncReadGraph graph, Resource subject, final AsyncMultiProcedure<Resource> procedure) {
217 assert(subject != null);
219 final ForEachObjectProcedure proc = (ForEachObjectProcedure)procedure;
220 // final RelationInfo info = proc.info;
222 final ReadGraphImpl impl = (ReadGraphImpl)graph;
223 final int subjectId = ((ResourceImpl)subject).id;
225 // int callerThread = impl.callerThread;
226 // int suggestSchedule = (subjectId>>16) & queryProvider2.THREAD_MASK;
230 // if(callerThread == suggestSchedule) {
232 // if(info.isFunctional) {
233 // querySupport.getObjects4(impl, subjectId, proc);
235 session.querySupport.getObjects4(impl, subjectId, proc);
240 // impl.state.barrier.inc();
241 // impl.state.barrier.dec(callerThread);
243 // queryProvider2.schedule(callerThread, new SessionTask(suggestSchedule) {
246 // public void run(int thread) {
248 // impl.state.barrier.inc(thread);
249 // impl.state.barrier.dec();
251 // if(info.isFunctional) {
252 // querySupport.getObjects4(impl.newAsync(thread), subjectId, proc);
254 // querySupport.getObjects4(impl.newAsync(thread), subjectId, proc);
260 // public String toString() {
271 public <C> void forEachObjectCompiled(AsyncReadGraph graph, Resource subject, C context, final AsyncContextMultiProcedure<C, Resource> procedure) {
273 assert(subject != null);
275 final ForEachObjectContextProcedure<C> proc = (ForEachObjectContextProcedure<C>)procedure;
276 final RelationInfo info = proc.info;
278 final ReadGraphImpl impl = (ReadGraphImpl)graph;
279 final int subjectId = ((ResourceImpl)subject).id;
281 // int callerThread = impl.callerThread;
282 // int suggestSchedule = (subjectId>>16) & queryProvider2.THREAD_MASK;
286 if(info.isFunctional) {
287 session.querySupport.getObjects4(impl, subjectId, context, proc);
289 session.querySupport.getObjects4(impl, subjectId, context, proc);
295 public <T> void forPossibleRelatedValueCompiled(AsyncReadGraph graph, Resource subject, final AsyncProcedure<T> procedure) {
297 assert(subject != null);
299 final ForPossibleRelatedValueProcedure<T> proc = (ForPossibleRelatedValueProcedure<T>)procedure;
300 final RelationInfo info = proc.info;
302 final ReadGraphImpl impl = (ReadGraphImpl)graph;
303 final int subjectId = ((ResourceImpl)subject).id;
305 // int callerThread = impl.callerThread;
306 // int suggestSchedule = (subjectId>>16) & session.queryProvider2.THREAD_MASK;
310 // if(callerThread == suggestSchedule) {
312 if(info.isFunctional) {
313 getRelatedValue4(impl, subjectId, proc);
315 getRelatedValue4(impl, subjectId, proc);
320 // impl.state.barrier.inc();
321 // impl.state.barrier.dec(callerThread);
323 // queryProvider2.schedule(callerThread, new SessionTask(suggestSchedule) {
326 // public void run(int thread) {
328 // impl.state.barrier.inc(thread);
329 // impl.state.barrier.dec();
331 // if(info.isFunctional) {
332 // getRelatedValue4(impl.newAsync(thread), subjectId, proc);
334 // getRelatedValue4(impl.newAsync(thread), subjectId, proc);
340 // public String toString() {
351 public <C, T> void forPossibleRelatedValueCompiled(AsyncReadGraph graph, Resource subject, C context, final AsyncContextProcedure<C, T> procedure) {
353 assert(subject != null);
355 final ForPossibleRelatedValueContextProcedure<C, T> proc = (ForPossibleRelatedValueContextProcedure<C, T>)procedure;
356 final RelationInfo info = proc.info;
358 final ReadGraphImpl impl = (ReadGraphImpl)graph;
359 final int subjectId = ((ResourceImpl)subject).id;
361 // int callerThread = impl.callerThread;
362 // int suggestSchedule = (subjectId>>16) & session.queryProvider2.THREAD_MASK;
366 if(info.isFunctional) {
367 getRelatedValue4(impl, subjectId, context, proc);
369 getRelatedValue4(impl, subjectId, context, proc);
375 public <T> void forPossibleType(final AsyncReadGraph graph, Resource subject, final AsyncProcedure<Resource> procedure) {
377 assert(subject != null);
379 final ReadGraphImpl impl = (ReadGraphImpl)graph;
380 final int subjectId = ((ResourceImpl)subject).id;
384 final ClusterI cluster = session.clusterTable.getClusterByResourceKey(subjectId);
385 if(!cluster.isLoaded()) {
387 // impl.state.inc(0);
389 session.queryProvider2.requestCluster(impl, cluster.getClusterId(), new Runnable() {
396 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
397 procedure.execute(graph, new ResourceImpl(session.resourceSupport, result));
399 // impl.state.dec(0);
401 } catch (DatabaseException e) {
411 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
412 procedure.execute(graph, new ResourceImpl(session.resourceSupport, result));
416 } catch (DatabaseException e) {
425 public <C> void forPossibleDirectType(final AsyncReadGraph graph, Resource subject, final C context, final AsyncContextProcedure<C, Resource> procedure) {
427 assert(subject != null);
429 final ReadGraphImpl impl = (ReadGraphImpl)graph;
430 final int subjectId = ((ResourceImpl)subject).id;
434 final ClusterI cluster = session.clusterTable.getClusterByResourceKey(subjectId);
435 if(!cluster.isLoaded()) {
437 // impl.state.inc(0);
439 session.queryProvider2.requestCluster(impl, cluster.getClusterId(), new Runnable() {
446 ClusterI.CompleteTypeEnum type = cluster.getCompleteType(subjectId, session.clusterTranslator);
447 if(ClusterI.CompleteTypeEnum.InstanceOf == type) {
448 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
449 procedure.execute(graph, context, new ResourceImpl(session.resourceSupport, result));
451 procedure.execute(graph, context, null);
454 // impl.state.dec(0);
456 } catch (DatabaseException e) {
466 ClusterI.CompleteTypeEnum type = cluster.getCompleteType(subjectId, session.clusterTranslator);
467 if(ClusterI.CompleteTypeEnum.InstanceOf == type) {
468 int result = cluster.getCompleteObjectKey(subjectId, session.clusterTranslator);
469 procedure.execute(graph, context, new ResourceImpl(session.resourceSupport, result));
471 procedure.execute(graph, context, null);
476 } catch (DatabaseException e) {
478 procedure.execute(graph, context, null);
480 } catch (Throwable t) {
483 procedure.execute(graph, context, null);
490 private <C, T> void getRelatedValue4(final ReadGraphImpl graph, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
494 final int predicate = procedure.predicateKey;
498 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
499 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
500 g -> getRelatedValue4(g, subject, context, procedure)
505 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
506 for (int id : g.getObjects(subject, predicate)) {
508 procedure.exception(graph, new DatabaseException("Multiple objects"));
519 procedure.exception(graph, new DatabaseException("No objects for " + subject ));
525 getValue4(graph, null, result, context, procedure);
532 final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
533 if(!cluster.isLoaded()) {
534 cluster.load(session.clusterTranslator, () -> getRelatedValue4(graph, subject, context, procedure));
538 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
540 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
541 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
542 g -> getRelatedValue4(g, subject, context, procedure)
547 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
548 for (int id : g.getObjects(subject, predicate)) {
550 procedure.exception(graph, new DatabaseException("Multiple objects"));
559 getRelatedDirectValue4(graph, cluster, subject, result, context, procedure);
563 getRelatedDirectValue4(graph, cluster, subject, 0, context, procedure);
569 @SuppressWarnings("unchecked")
570 private <T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
572 Object result = null;
576 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
577 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
578 g -> getValue4(g, containerCluster, subject, procedure)
583 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
584 Object value = g.getValue(subject);
587 procedure.exception(graph, new DatabaseException("Multiple values"));
596 procedure.execute(graph, (T)"name");
602 ClusterImpl cluster = containerCluster;
603 if(!containerCluster.contains(subject)) {
604 cluster = session.clusterTable.getClusterByResourceKey(subject);
605 if(!cluster.isLoaded()) {
606 cluster.load(session.clusterTranslator, new Runnable() {
610 getValue4(graph, containerCluster, subject, procedure);
618 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
620 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
621 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
622 g -> getValue4(g, containerCluster, subject, procedure)
627 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
628 Object value = g.getValue(subject);
631 procedure.exception(graph, new DatabaseException("Multiple values"));
642 procedure.execute(graph, (T)result);
643 // graph.state.barrier.dec();
647 if(ClusterTypeEnum.SMALL == cluster.getType())
648 getDirectValue4(graph, (ClusterSmall)cluster, subject, procedure);
650 getDirectValue4(graph, (ClusterBig)cluster, subject, procedure);
655 if(ClusterTypeEnum.SMALL == cluster.getType())
656 getDirectValue4(graph, (ClusterSmall)cluster, subject, procedure);
658 getDirectValue4(graph, (ClusterBig)cluster, subject, procedure);
664 @SuppressWarnings("unchecked")
665 private <C, T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
667 Object result = null;
671 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
672 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
673 g -> getValue4(g, containerCluster, subject, context, procedure)
678 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
679 Object value = g.getValue(subject);
682 procedure.exception(graph, new DatabaseException("Multiple values"));
691 procedure.execute(graph, context, (T)"name");
697 ClusterImpl cluster = containerCluster;
698 if(!containerCluster.contains(subject)) {
699 cluster = session.clusterTable.getClusterByResourceKey(subject);
700 if(!cluster.isLoaded()) {
701 cluster.load(session.clusterTranslator, new Runnable() {
705 getValue4(graph, containerCluster, subject, context, procedure);
713 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
715 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
716 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
717 g -> getValue4(g, containerCluster, subject, context, procedure)
722 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
723 Object value = g.getValue(subject);
726 procedure.exception(graph, new DatabaseException("Multiple values"));
737 procedure.execute(graph, context, (T)result);
738 // graph.state.barrier.dec();
742 if(ClusterTypeEnum.SMALL == cluster.getType())
743 getDirectValue4(graph, (ClusterSmall)cluster, subject, context, procedure);
745 getDirectValue4(graph, (ClusterBig)cluster, subject, context, procedure);
750 if(ClusterTypeEnum.SMALL == cluster.getType())
751 getDirectValue4(graph, (ClusterSmall)cluster, subject, context, procedure);
753 getDirectValue4(graph, (ClusterBig)cluster, subject, context, procedure);
759 private <T> void getRelatedDirectValue4(final ReadGraphImpl graph, final ClusterImpl cluster, final int subject, final int result, final ForPossibleRelatedValueProcedure<T> procedure) {
763 int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
766 procedure.exception(graph, new DatabaseException("No objects " + subject + " " + procedure.predicateKey));
769 getValue4(graph, cluster, result, procedure);
773 getValue4(graph, cluster, so, procedure);
775 procedure.exception(graph, new DatabaseException("Multiple objects"));
780 } catch (DatabaseException e) {
786 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) {
790 int so = cluster.getSingleObject(subject, procedure, session.clusterTranslator);
793 procedure.exception(graph, new NoSingleResultException("No objects " + subject + " " + procedure.predicateKey, result));
796 getValue4(graph, cluster, result, context, procedure);
800 getValue4(graph, cluster, so, context, procedure);
802 procedure.exception(graph, new NoSingleResultException("Multiple objects for " + subject + " " + procedure.predicateKey, result));
807 } catch (DatabaseException e) {
808 LOGGER.error("Could not compute related value for subject {} with predicate {}", subject, procedure.predicateKey);
813 public <T> void getRelatedValue4(final ReadGraphImpl graph, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
817 final int predicate = procedure.predicateKey;
821 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
822 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
823 g -> getRelatedValue4(g, subject, procedure)
828 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
829 for (int id : g.getObjects(subject, predicate)) {
831 procedure.exception(graph, new DatabaseException("Multiple objects"));
842 procedure.exception(graph, new DatabaseException("No objects for " + subject ));
848 getValue4(graph, null, result, procedure);
855 final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
856 if(!cluster.isLoaded()) {
857 cluster.load(session.clusterTranslator, new Runnable() {
861 getRelatedValue4(graph, subject, procedure);
868 if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
870 if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
871 SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
872 g -> getRelatedValue4(graph, subject, procedure)
877 for(TransientGraph g : session.virtualGraphServerSupport.providers) {
878 for (int id : g.getObjects(subject, predicate)) {
880 procedure.exception(graph, new DatabaseException("Multiple objects"));
889 getRelatedDirectValue4(graph, cluster, subject, result, procedure);
893 getRelatedDirectValue4(graph, cluster, subject, 0, procedure);
899 private <C, T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
902 byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
903 @SuppressWarnings("unchecked")
904 T value = (T)utf(bytes, 0);
905 procedure.execute(graph, context, value);
906 } catch (DatabaseException e) {
907 procedure.execute(graph, context, null);
914 private <T> void getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
917 byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
918 @SuppressWarnings("unchecked")
919 T value = (T)utf(bytes, 0);
920 procedure.execute(graph, value);
921 } catch (DatabaseException e) {
922 procedure.execute(graph, null);
929 private <C, T> void getDirectValue4(final ReadGraphImpl graph, final ClusterBig cluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
932 byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
934 procedure.execute(graph, context, null);
936 @SuppressWarnings("unchecked")
937 T value = (T)utf(bytes, 0);
938 procedure.execute(graph, context, value);
940 } catch (DatabaseException e) {
941 procedure.execute(graph, context, null);
948 private <T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
950 // Note: this code avoids creating an intermediate byte[]
951 // to store the encoded string bytes and reads the UTF string
952 // from the value table byte[] directly into String instead.
954 ResourceTableSmall rt = cluster.resourceTable;
955 ValueTableSmall vt = cluster.valueTable;
957 byte[] bs = vt.table;
958 long[] ls = rt.table;
960 int index = ((subject&0xFFF) << 1) - 1 + rt.offset;
961 int valueIndex = ((int)(ls[index] >>> 24) & 0x3FFFFF) + vt.offset;
963 int size = bs[valueIndex++];
964 if (size < 0) // two byte size
965 size = (int)(((size & 0x7F) << 8) | (bs[valueIndex++] & 0xFF));
967 throw new DatabaseException("No value for " + subject);
969 @SuppressWarnings("unchecked")
970 T t = (T) utf(bs, valueIndex);
972 procedure.execute(graph, t);
973 } catch (DatabaseException e) {
974 procedure.exception(graph, e);
978 final private String utf(byte[] bytes, int offset) throws AssumptionException {
980 if(bytes == null) return null;
982 // Read databoard int32 using Length encoding
983 // https://dev.simantics.org/index.php/Databoard_Specification#Length
985 int length = bytes[index++]&0xff;
991 length += ((bytes[index++]&0xff)<<3);
992 length += ((bytes[index++]&0xff)<<11);
993 length += ((bytes[index++]&0xff)<<19);
994 length += 0x10204080;
998 length += ((bytes[index++]&0xff)<<4);
999 length += ((bytes[index++]&0xff)<<12);
1000 length += ((bytes[index++]&0xff)<<20);
1006 length += ((bytes[index++]&0xff)<<5);
1007 length += ((bytes[index++]&0xff)<<13);
1013 length += ((bytes[index++]&0xff)<<6);
1018 // Copied from DataInputStream
1019 int utflen = length;
1020 char[] chararr = new char[utflen];
1022 int c, char2, char3;
1024 int target = index + length;
1025 int chararr_count=0;
1027 while (count < target) {
1028 c = (int) bytes[count] & 0xff;
1031 chararr[chararr_count++]=(char)c;
1034 while (count < target) {
1035 c = (int) bytes[count] & 0xff;
1037 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
1040 chararr[chararr_count++]=(char)c;
1043 /* 110x xxxx 10xx xxxx*/
1046 throw new AssumptionException(
1047 "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
1048 char2 = (int) bytes[count-1];
1049 if ((char2 & 0xC0) != 0x80)
1050 throw new AssumptionException(
1051 "malformed input around byte " + count);
1052 chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
1056 /* 1110 xxxx 10xx xxxx 10xx xxxx */
1059 throw new AssumptionException(
1060 "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
1061 char2 = (int) bytes[count-2];
1062 char3 = (int) bytes[count-1];
1063 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
1064 throw new AssumptionException(
1065 "malformed input around byte " + (count-1));
1066 chararr[chararr_count++]=(char)(((c & 0x0F) << 12) |
1067 ((char2 & 0x3F) << 6) |
1068 ((char3 & 0x3F) << 0));
1071 /* 10xx xxxx, 1111 xxxx */
1072 throw new AssumptionException(
1073 "malformed input around byte " + count);
1077 // The number of chars produced may be less than utflen
1078 return new String(chararr, 0, chararr_count);