]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/DirectQuerySupportImpl.java
Backported b75a6bbc for release/1.32.0.2
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / DirectQuerySupportImpl.java
index 9d6b019e4a2d22de5a3954f77f125abde174a468..fe992c4e9aa68ee6eebeae97234bdaa8b1a2cbf4 100644 (file)
@@ -7,6 +7,7 @@ import org.simantics.db.RelationInfo;
 import org.simantics.db.Resource;
 import org.simantics.db.common.procedure.wrapper.NoneToAsyncProcedure;
 import org.simantics.db.common.procedure.wrapper.SyncToAsyncProcedure;
+import org.simantics.db.exception.AssumptionException;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.impl.ClusterI;
 import org.simantics.db.impl.ClusterI.ClusterTypeEnum;
@@ -30,8 +31,14 @@ import org.simantics.db.procore.cluster.ResourceTableSmall;
 import org.simantics.db.procore.cluster.ValueTableSmall;
 import org.simantics.db.request.AsyncRead;
 import org.simantics.db.service.DirectQuerySupport;
-import org.simantics.utils.datastructures.Callback;
 
+/**
+ * Note that the direct value retrieval in this implementation only supports
+ * String-type literals - nothing else!
+ * 
+ * This implementation is mainly intended for optimizing database indexing
+ * performance.
+ */
 public class DirectQuerySupportImpl implements DirectQuerySupport {
 
        final private SessionImplSocket session;
@@ -484,14 +491,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getRelatedValue4(graph, subject, context, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
+                                   g -> getRelatedValue4(g, subject, context, procedure)
+                               );
                                return;
                        }
                        
@@ -524,28 +526,16 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                
         final org.simantics.db.procore.cluster.ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
         if(!cluster.isLoaded()) {
-               cluster.load(session.clusterTranslator, new Runnable() {
-
-                               @Override
-                               public void run() {
-                                       getRelatedValue4(graph, subject, context, procedure);
-                               }
-                       
-               });
+               cluster.load(session.clusterTranslator, () -> getRelatedValue4(graph, subject, context, procedure));
                return;
         }
         
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
                        
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getRelatedValue4(graph, subject, context, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
+                                   g -> getRelatedValue4(g, subject, context, procedure)
+                               );
                                return;
                        }
                
@@ -571,6 +561,7 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                
        }
        
+       @SuppressWarnings("unchecked")
        private <T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
                
                Object result = null;
@@ -578,14 +569,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getValue4(graph, containerCluster, subject, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, 
+                                   g -> getValue4(g, containerCluster, subject, procedure)
+                           );
                                return;
                        }
                        
@@ -627,14 +613,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getValue4(graph, containerCluster, subject, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
+                           g -> getValue4(g, containerCluster, subject, procedure)
+                           );
                                return;
                        }
                
@@ -675,6 +656,7 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
        
        }
        
+       @SuppressWarnings("unchecked")
        private <C, T> void getValue4(final ReadGraphImpl graph, final ClusterImpl containerCluster, final int subject, final C context, final ForPossibleRelatedValueContextProcedure<C, T> procedure) {
                
                Object result = null;
@@ -682,14 +664,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getValue4(graph, containerCluster, subject, context, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
+                                   g -> getValue4(g, containerCluster, subject, context, procedure)
+                           );
                                return;
                        }
                        
@@ -731,14 +708,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getValue4(graph, containerCluster, subject, context, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject,
+                                    g -> getValue4(g, containerCluster, subject, context, procedure)
+                           );
                                return;
                        }
                
@@ -842,14 +814,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                if(subject < 0) {
 
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getRelatedValue4(graph, subject, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
+                                   g -> getRelatedValue4(g, subject, procedure)
+                           );
                                return;
                        }
                        
@@ -896,14 +863,9 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
         if(cluster.hasVirtual() && session.virtualGraphServerSupport.virtuals.contains(subject)) {
                        
                        if(!SessionImplSocket.areVirtualStatementsLoaded(session.virtualGraphServerSupport, subject, predicate)) {
-                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate, new Callback<ReadGraphImpl>()  {
-
-                                       @Override
-                                       public void run(ReadGraphImpl graph) {
-                                               getRelatedValue4(graph, subject, procedure);
-                                       }
-                                       
-                               });
+                           SessionImplSocket.loadVirtualStatements(session.virtualGraphServerSupport, graph, subject, predicate,
+                                   g -> getRelatedValue4(graph, subject, procedure)
+                           );
                                return;
                        }
                
@@ -933,7 +895,8 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                
                try {
                        byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
-                       T value = (T)utf(bytes);
+                       @SuppressWarnings("unchecked")
+                       T value = (T)utf(bytes, 0);
                        procedure.execute(graph, context, value);
                } catch (DatabaseException e) {
                        procedure.execute(graph, context, null);
@@ -947,7 +910,8 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                
                try {
                        byte[] bytes = cluster.getValue(subject, session.clusterTranslator);
-                       T value = (T)utf(bytes);
+                       @SuppressWarnings("unchecked")
+                       T value = (T)utf(bytes, 0);
                        procedure.execute(graph, value);
                } catch (DatabaseException e) {
                        procedure.execute(graph, null);
@@ -964,7 +928,8 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                        if(bytes == null) {
                                procedure.execute(graph, context, null);
                        } else {
-                               T value = (T)utf(bytes);
+                               @SuppressWarnings("unchecked")
+                               T value = (T)utf(bytes, 0);
                                procedure.execute(graph, context, value);
                        }
                } catch (DatabaseException e) {
@@ -975,38 +940,43 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                
        }
        
-       private final char[] chars = new char[1024];
-       
        private <T> void getDirectValue4(final ReadGraphImpl graph, final ClusterSmall cluster, final int subject, final ForPossibleRelatedValueProcedure<T> procedure) {
+               try {
+                       // Note: this code avoids creating an intermediate byte[]
+                       // to store the encoded string bytes and reads the UTF string
+                       // from the value table byte[] directly into String instead.
 
-               ResourceTableSmall rt = cluster.resourceTable;
-               ValueTableSmall vt = cluster.valueTable;
-
-               byte[] bs = vt.table;
-               long[] ls = rt.table;
+                       ResourceTableSmall rt = cluster.resourceTable;
+                       ValueTableSmall vt = cluster.valueTable;
 
-               int index = ((subject&0xFFFF) << 1) - 1 + rt.offset;
+                       byte[] bs = vt.table;
+                       long[] ls = rt.table;
 
-               int valueIndex = (int)(ls[index] >>> 24) & 0x3FFFFF + vt.offset;
+                       int index = ((subject&0xFFF) << 1) - 1 + rt.offset;
+                       int valueIndex = ((int)(ls[index] >>> 24) & 0x3FFFFF) + vt.offset;
 
-               int size = (int)bs[valueIndex++]-1;
-               valueIndex++;
-               for(int i=0;i<size;i++) {
-                       chars[i] = (char)bs[valueIndex++];
-               }
+                       int size = bs[valueIndex++];
+                       if (size < 0) // two byte size
+                               size = (int)(((size & 0x7F) << 8) | (bs[valueIndex++] & 0xFF));
+                       if (size <= 0)
+                               throw new DatabaseException("No value for " + subject); 
 
-               T value = (T)new String(chars, 0, size);
+                       @SuppressWarnings("unchecked")
+                       T t = (T) utf(bs, valueIndex);
 
-               procedure.execute(graph, value);
-//             graph.dec();
-               
+                       procedure.execute(graph, t);
+               } catch (DatabaseException e) {
+                       procedure.exception(graph, e);
+               }
        }
 
-       final private String utf(byte[] bytes) {
-               
+       final private String utf(byte[] bytes, int offset) throws AssumptionException {
+
                if(bytes == null) return null;
-               
-               int index = 0;
+
+               // Read databoard int32 using Length encoding
+               // https://dev.simantics.org/index.php/Databoard_Specification#Length
+               int index = offset;
                int length = bytes[index++]&0xff; 
                if(length >= 0x80) {
                        if(length >= 0xc0) {
@@ -1039,42 +1009,68 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
                                length += 0x80;
                        }
                }
-               
-               int i = 0;
-               int target = length+index;
-               while(index < target) {
-                       int c = bytes[index++]&0xff;
-                       if(c <= 0x7F) {
-                               chars[i++] = (char)(c&0x7F);
-                       } else if (c > 0x07FF) {
-                               int c2 = bytes[index++]&0xff;
-                               int c3 = bytes[index++]&0xff;
-                               chars[i++] = (char)(((c&0xf)<<12) + ((c2&0x3f)<<6) + (c3&0x3f)); 
-                       } else {
-                               int c2 = bytes[index++]&0xff;
-                               chars[i++] = (char)(((c&0x1f)<<6) + (c2&0x3f)); 
+
+               // Copied from DataInputStream
+               int utflen = length;
+               char[] chararr = new char[utflen];
+
+               int c, char2, char3;
+               int count = index;
+               int target = index + length;
+               int chararr_count=0;
+
+               while (count < target) {
+                       c = (int) bytes[count] & 0xff;
+                       if (c > 127) break;
+                       count++;
+                       chararr[chararr_count++]=(char)c;
+               }
+
+               while (count < target) {
+                       c = (int) bytes[count] & 0xff;
+                       switch (c >> 4) {
+                       case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+                               /* 0xxxxxxx*/
+                               count++;
+                               chararr[chararr_count++]=(char)c;
+                               break;
+                       case 12: case 13:
+                               /* 110x xxxx   10xx xxxx*/
+                               count += 2;
+                               if (count > target)
+                                       throw new AssumptionException(
+                                                       "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
+                               char2 = (int) bytes[count-1];
+                               if ((char2 & 0xC0) != 0x80)
+                                       throw new AssumptionException(
+                                                       "malformed input around byte " + count); 
+                               chararr[chararr_count++]=(char)(((c & 0x1F) << 6) | 
+                                               (char2 & 0x3F));  
+                               break;
+                       case 14:
+                               /* 1110 xxxx  10xx xxxx  10xx xxxx */
+                               count += 3;
+                               if (count > target)
+                                       throw new AssumptionException(
+                                                       "malformed input: partial character at end (" + (count-index) + " > " + utflen + ")");
+                               char2 = (int) bytes[count-2];
+                               char3 = (int) bytes[count-1];
+                               if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+                                       throw new AssumptionException(
+                                                       "malformed input around byte " + (count-1));
+                               chararr[chararr_count++]=(char)(((c     & 0x0F) << 12) |
+                                               ((char2 & 0x3F) << 6)  |
+                                               ((char3 & 0x3F) << 0));
+                               break;
+                       default:
+                               /* 10xx xxxx,  1111 xxxx */
+                               throw new AssumptionException(
+                                               "malformed input around byte " + count);
                        }
-                       
-                       
-//                     if (!((c >= 0x0001) && (c <= 0x007F))) {
-//                     } else {
-//                     }
-//                     
-//                             if ((c >= 0x0001) && (c <= 0x007F)) {
-//                                     bytearr[byteIndex++] = (byte)( c );
-//                             } else if (c > 0x07FF) {
-//                                     bytearr[byteIndex++] = (byte)(0xE0 | ((c >> 12) & 0x0F));
-//                                     bytearr[byteIndex++] = (byte)(0x80 | ((c >>  6) & 0x3F));
-//                                     bytearr[byteIndex++] = (byte)(0x80 | ((c >>  0) & 0x3F));
-//                             } else {
-//                                     bytearr[byteIndex++] = (byte)(0xC0 | ((c >>  6) & 0x1F));
-//                                     bytearr[byteIndex++] = (byte)(0x80 | ((c >>  0) & 0x3F));
-//                             }
-//                     }
-                       
-                       
                }
-               return new String(chars, 0, i);
+
+               // The number of chars produced may be less than utflen
+               return new String(chararr, 0, chararr_count);
        }
-       
+
 }