Improve performance of CommandMetadata (de)serialization 58/1958/1
authorjsimomaa <jani.simomaa@gmail.com>
Fri, 27 Jul 2018 06:59:25 +0000 (09:59 +0300)
committerjsimomaa <jani.simomaa@gmail.com>
Fri, 27 Jul 2018 06:59:25 +0000 (09:59 +0300)
gitlab #60

Change-Id: I499dc390e84a733e9a890164695a79ad2a40e05f

bundles/org.simantics.db.common/src/org/simantics/db/common/CommandMetadata.java

index 03c9ce9aadefc50ae4c689297a6ce181b075fd6e..d0c3a62b4af37172c2911f490c2a4df6cbc313ec 100644 (file)
@@ -1,57 +1,86 @@
 package org.simantics.db.common;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.databoard.binding.Binding;
-import org.simantics.databoard.serialization.SerializationException;
 import org.simantics.databoard.serialization.Serializer;
 import org.simantics.db.Metadata;
 import org.simantics.db.Session;
 import org.simantics.db.WriteGraph;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.service.Bytes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class CommandMetadata implements Metadata {
+import gnu.trove.list.array.TByteArrayList;
+
+public final class CommandMetadata implements Metadata {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CommandMetadata.class);
 
     public static final boolean DEBUG = false;
     public static final String RESET_COMMAND = "// RESET";
-    
+
     private static final Binding BINDING = 
             Bindings.getBindingUnchecked(CommandMetadata.class);
     private static final Serializer SERIALIZER = 
             Bindings.getSerializerUnchecked(BINDING);
-    
+
     public List<Command> commands;
-    
-    public static class Command {
+
+    public static final class Command {
         public long modelId;
         public String command;
-        
-        public Command() {         
+
+        public Command() {
         }
-        
+
         public Command(long modelId, String command) {
             super();
             this.modelId = modelId;
             this.command = command;
         }
     }
-    
+
     public CommandMetadata() {
     }
 
     @Override
     public byte[] serialise(Session session) {
         try {
-            return SERIALIZER.serialize(this);
-        } catch (IOException e) {
-            e.printStackTrace();
-            throw new RuntimeException(e);
+            TByteArrayList commandsSerialized = new TByteArrayList(4096);
+            byte[] bytes = new byte[8];
+
+            int commandsSize = commands.size();
+            Bytes.writeLE(bytes, 0, commandsSize);
+            commandsSerialized.add(bytes, 0, 4);
+
+            for (Command command : commands) {
+                Bytes.writeLE8(bytes, 0, command.modelId);
+                commandsSerialized.add(bytes);
+                byte[] commandBytes = command.command.getBytes(StandardCharsets.UTF_8);
+                Bytes.writeLE(bytes, 0, commandBytes.length);
+                commandsSerialized.add(bytes, 0, 4);
+                commandsSerialized.add(commandBytes);
+            }
+            return commandsSerialized.toArray();
+        } catch (Exception ee) {
+            // Ok, backwards compatibility required
+            // This is rather slow operation hence the new implementation above
+            try {
+                return SERIALIZER.serialize(this);
+            } catch (IOException e) {
+                LOGGER.error("Could not serialize", e);
+                LOGGER.error("Original exception for new serialisation", ee);
+                throw new RuntimeException(e);
+            }
         }
     }
-    
+
     public static CommandMetadata deserialise(Session session, byte[] input) {
         if(input == null) {
             CommandMetadata metadata = new CommandMetadata();
@@ -59,13 +88,36 @@ public class CommandMetadata implements Metadata {
             return metadata;
         }
         try {
-            return (CommandMetadata)SERIALIZER.deserialize(input);
-        } catch (SerializationException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
+            int byteIndex = 0;
+            int commandsSize = Bytes.readLE4(input, byteIndex);
+            byteIndex += 4;
+            
+            List<Command> commands = new ArrayList<>(commandsSize);
+            for (int i = 0; i < commandsSize; i++) {
+                long modelId = Bytes.readLE8(input, byteIndex);
+                byteIndex += 8;
+                int commandsLength = Bytes.readLE4(input, byteIndex);
+                byteIndex += 4;
+                
+                String command = new String(input, byteIndex, commandsLength);
+                byteIndex += commandsLength;
+                Command comm = new Command(modelId, command);
+                commands.add(comm);
+            }
+            CommandMetadata metadata = new CommandMetadata();
+            metadata.commands = commands;
+            return metadata;
+        } catch (Exception ee) {
+            // Ok, backwards compatibility required
+            // This is rather slow operation hence the new implementation above
+            try {
+                return (CommandMetadata)SERIALIZER.deserialize(input);
+            } catch (Exception e) {
+                LOGGER.error("Could not deserialise", e);
+                LOGGER.error("Original exception for new deserialisation", ee);
+            }
+            return null;
         }
-        return null;
     }
 
     public CommandMetadata add(Command command) {