]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Backported b75a6bbc for release/1.34.1 31/2031/2
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Sun, 26 Aug 2018 12:28:01 +0000 (15:28 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Sun, 26 Aug 2018 12:38:51 +0000 (12:38 +0000)
Previous too-optimized implementation had multiple flaws:
* Index calculation did not have enough parenthesis in it which meant
  that the value table index was sometimes calculated incorrectly.
  This lead to string literal values being read incorrectly.
* Did not take into account string literals longer than 127 characters
* Did not take into account that string literals are modified-utf-8
  encoded and simply decoded them as US-ASCII bytes. Essentially all
  resources with name containing special characters were indexed
  incorrectly up until now.

All of these flaws have been in the code for ages.

gitlab #86

Change-Id: Ibd5ecbaa1cdd1b8be759905bd8c29b9f8e012207
(cherry picked from commit cd47b6877cee258113eb00523701a57374becfd8)

bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/DirectQuerySupportImpl.java

index 0b640861e1d6af93255b25114c429b2f374ce54f..5f6c722acfdffa0d721b71b600cb8be99d51533e 100644 (file)
@@ -35,6 +35,13 @@ import org.simantics.db.service.DirectQuerySupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * 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 {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(DirectQuerySupportImpl.class);
@@ -559,6 +566,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;
@@ -653,6 +661,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;
@@ -891,7 +900,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);
@@ -905,7 +915,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);
@@ -922,7 +933,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) {
@@ -934,38 +946,42 @@ public class DirectQuerySupportImpl implements DirectQuerySupport {
        }
        
        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;
-               char[] chars = new char[size];
-               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);
+                       @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) throws AssumptionException {
+       final private String utf(byte[] bytes, int offset) throws AssumptionException {
 
                if(bytes == null) return null;
 
                // Read databoard int32 using Length encoding
                // https://dev.simantics.org/index.php/Databoard_Specification#Length
-               int index = 0;
+               int index = offset;
                int length = bytes[index++]&0xff; 
                if(length >= 0x80) {
                        if(length >= 0xc0) {