Include cached hash code in TransferableGraph1 extensions map 43/1543/2
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 9 Mar 2018 11:20:47 +0000 (13:20 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 9 Mar 2018 11:22:12 +0000 (13:22 +0200)
The cached hashcode is calculated before inserting the cached hash value
in the TransferableGraph1.extensions TreeMap. Reading and inspection
must be done with this in mind.

This cached value is used to optimize platform startup by removing the
need to calculate the TransferableGraph1 structure hashcode at runtime
which can be quite expensive because the standard databoard Bindings are
slow compared to optimal methods. Of course an optimized binding could
be used to speed the calculation up dramatically but it still can't beat
caching the final (immutable) hashCode value.

refs #7806

Change-Id: I9d4fc6549cba567f95b19f80bd15c1ccfbbedf07

bundles/org.simantics.graph.compiler/src/org/simantics/graph/compiler/GraphCompiler.java
bundles/org.simantics.graph/src/org/simantics/graph/representation/Extensions.java

index 98852bcefafc4962bc90e3e64ae4b15c1b1549d0..26663b08a2a5f288e9f38753ff53162045a82c02 100644 (file)
@@ -15,12 +15,11 @@ import java.util.Locale;
 import org.simantics.databoard.Bindings;
 import org.simantics.databoard.Files;
 import org.simantics.databoard.adapter.AdaptException;
+import org.simantics.databoard.binding.Binding;
 import org.simantics.databoard.binding.error.BindingException;
-import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
 import org.simantics.databoard.binding.mutable.Variant;
 import org.simantics.databoard.container.DataContainer;
 import org.simantics.databoard.container.DataContainers;
-import org.simantics.databoard.serialization.SerializationException;
 import org.simantics.graph.compiler.internal.parsing.Parsing;
 import org.simantics.graph.compiler.internal.procedures.AddConsistsOf;
 import org.simantics.graph.compiler.internal.procedures.ApplyTemplates;
@@ -39,6 +38,7 @@ import org.simantics.graph.compiler.internal.validation.ValidateGraph;
 import org.simantics.graph.query.CompositeGraph;
 import org.simantics.graph.query.Paths;
 import org.simantics.graph.query.TransferableGraphConversion;
+import org.simantics.graph.representation.Extensions;
 import org.simantics.graph.representation.TransferableGraph1;
 import org.simantics.graph.store.GraphStore;
 import org.simantics.ltk.FileSource;
@@ -62,10 +62,17 @@ public class GraphCompiler {
        }
        
        public static InputStream write(TransferableGraph1 tg) throws BindingException, IOException {
-               byte[] buffer = DataContainers.writeFile(
-                               new DataContainer("graph", 1, new Variant(TransferableGraph1.BINDING, tg))
-                               );
-               return new ByteArrayInputStream(buffer);
+               Binding binding = TransferableGraph1.BINDING;
+               int hashCode = binding.hashValue(tg);
+               tg.extensions.put(Extensions.CACHED_HASHCODE, new Variant(Bindings.INTEGER, hashCode));
+               try {
+                       byte[] buffer = DataContainers.writeFile(
+                                       new DataContainer("graph", 1, new Variant(TransferableGraph1.BINDING, tg))
+                                       );
+                       return new ByteArrayInputStream(buffer);
+               } finally {
+                       tg.extensions.remove(Extensions.CACHED_HASHCODE);
+               }
        }
        
        public static CompilationResult compile(
@@ -200,9 +207,10 @@ public class GraphCompiler {
        
        public static void reportTime(String taskName, long beginTime, long endTime) {
                StringBuilder sb = new StringBuilder();
-           Formatter formatter = new Formatter(sb, Locale.US);
-           formatter.format("%-25s %8.4f ms", taskName, (endTime - beginTime)*1e-6);
-                  
+               @SuppressWarnings("resource")
+               Formatter formatter = new Formatter(sb, Locale.US);
+               formatter.format("%-25s %8.4f ms", taskName, (endTime - beginTime)*1e-6);
+
                out.println(sb.toString());
        }
        
index 8a8cb3d568fa571e905a8bfc6a8c53245c77f856..375fb1416899f57bb40c66761b31504773bef870 100644 (file)
@@ -2,18 +2,33 @@ package org.simantics.graph.representation;
 
 import java.util.TreeMap;
 
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
 import org.simantics.databoard.binding.mutable.Variant;
 
 public class Extensions {
-       
+
+       public static final Binding BINDING = Bindings.getBindingUnchecked(Extensions.class);
+
+       /**
+        * Used for storing a cached hash code computed from a
+        * {@link TransferableGraph1} instance <em>without</em> this cached hashcode
+        * key,value pair in the <code>extensions</code> map.
+        */
+       public final static String CACHED_HASHCODE = "cached.hashCode";
+
        final public static String CLUSTERING = "clustering";
        final public static String CLUSTER_SETS = "clusterSets";
        final public static int NO_CLUSTER_SET = -1;
        final public static int ROOT_LIBRARY_CLUSTER_SET = -1;
        final public static int INDEX_ROOT_CLUSTER_SET = -2;
-       
-       public TreeMap<String, Variant> map = new TreeMap<String, Variant>();
-       
+
+       public TreeMap<String, Variant> map;
+
+       public Extensions() {
+               this.map = new TreeMap<>();
+       }
+
        public Extensions(TreeMap<String, Variant> map) {
                this.map = map;
        }