TINKERPOP-1676 Improved speed and memory usage of GraphSON

This change is specific to TinkerGraph and the serialization of 
vertices/edges/properties. Removed a "middle layer" of JSON to Object 
serialization which was coercing JSON to Map first and then converting that to 
the graph elements. Also made deserializers cacheable.


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/251f5b7e
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/251f5b7e
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/251f5b7e

Branch: refs/heads/TINKERPOP-1681
Commit: 251f5b7e34e8ebd9a8bc36802e633be8c91eeb5e
Parents: 46e6e97
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue May 23 16:57:12 2017 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu May 25 14:52:30 2017 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   1 +
 .../io/graphson/AbstractObjectDeserializer.java |   5 +
 .../io/graphson/GraphSONSerializersV2d0.java    | 164 +++++++++++++++----
 .../structure/TinkerIoRegistryV2d0.java         |   5 +
 4 files changed, 145 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/251f5b7e/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 77d612e..f0d7b17 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.5 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Improved performance and memory usage of GraphSON when serializing 
`TinkerGraph` and graph elements.
 * Removed use of `stream()` in `DetachedEdge` and `DetachedVertex`.
 * Deprecated a constructor in `DetachedEdge` that made use of `Pair` in favor 
of a new one that just uses the objects that were in the `Pair`.
 * Improved error messaging on the `g.addV(Object...)` when passing an invalid 
arguments.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/251f5b7e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractObjectDeserializer.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractObjectDeserializer.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractObjectDeserializer.java
index bd7f4b6..9e4e102 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractObjectDeserializer.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractObjectDeserializer.java
@@ -47,5 +47,10 @@ public abstract class AbstractObjectDeserializer<T> extends 
StdDeserializer<T> {
         return createObject(mapData);
     }
 
+    @Override
+    public boolean isCachable() {
+        return true;
+    }
+
     public abstract T createObject(final Map<String, Object> data);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/251f5b7e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java
index 9a27279..0008d3a 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java
@@ -43,7 +43,9 @@ import 
org.apache.tinkerpop.shaded.jackson.core.JsonGenerationException;
 import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
 import org.apache.tinkerpop.shaded.jackson.core.JsonParser;
 import org.apache.tinkerpop.shaded.jackson.core.JsonProcessingException;
+import org.apache.tinkerpop.shaded.jackson.core.JsonToken;
 import org.apache.tinkerpop.shaded.jackson.databind.DeserializationContext;
+import org.apache.tinkerpop.shaded.jackson.databind.JavaType;
 import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
 import org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer;
 import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
@@ -416,52 +418,117 @@ class GraphSONSerializersV2d0 {
 
     //////////////////////////// DESERIALIZERS ///////////////////////////
 
-
-    static class VertexJacksonDeserializer extends 
AbstractObjectDeserializer<Vertex> {
+    static class VertexJacksonDeserializer extends StdDeserializer<Vertex> {
 
         public VertexJacksonDeserializer() {
             super(Vertex.class);
         }
 
+        public Vertex deserialize(final JsonParser jsonParser, final 
DeserializationContext deserializationContext) throws IOException, 
JsonProcessingException {
+            final JavaType propertiesType = 
deserializationContext.getConfig().getTypeFactory().constructMapType(HashMap.class,
 String.class, Object.class);
+
+            Object id = null;
+            String label = null;
+            Map<String, Object> properties = null;
+            while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+                if (jsonParser.getCurrentName().equals(GraphSONTokens.ID)) {
+                    jsonParser.nextToken();
+                    id = deserializationContext.readValue(jsonParser, 
Object.class);
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.LABEL)) {
+                    jsonParser.nextToken();
+                    label = jsonParser.getText();
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.PROPERTIES)) {
+                    jsonParser.nextToken();
+                    properties = deserializationContext.readValue(jsonParser, 
propertiesType);
+                }
+            }
+
+            return new DetachedVertex(id, label, properties);
+        }
+
         @Override
-        public Vertex createObject(final Map<String, Object> vertexData) {
-            return new DetachedVertex(
-                    vertexData.get(GraphSONTokens.ID),
-                    vertexData.get(GraphSONTokens.LABEL).toString(),
-                    (Map<String, Object>) 
vertexData.get(GraphSONTokens.PROPERTIES)
-            );
+        public boolean isCachable() {
+            return true;
         }
     }
 
-    static class EdgeJacksonDeserializer extends 
AbstractObjectDeserializer<Edge> {
+    static class EdgeJacksonDeserializer extends StdDeserializer<Edge> {
 
         public EdgeJacksonDeserializer() {
             super(Edge.class);
         }
 
         @Override
-        public Edge createObject(final Map<String, Object> edgeData) {
-            return new DetachedEdge(
-                    edgeData.get(GraphSONTokens.ID),
-                    edgeData.get(GraphSONTokens.LABEL).toString(),
-                    (Map) edgeData.get(GraphSONTokens.PROPERTIES),
-                    Pair.with(edgeData.get(GraphSONTokens.OUT), 
edgeData.get(GraphSONTokens.OUT_LABEL).toString()),
-                    Pair.with(edgeData.get(GraphSONTokens.IN), 
edgeData.get(GraphSONTokens.IN_LABEL).toString())
-            );
+        public Edge deserialize(final JsonParser jsonParser, final 
DeserializationContext deserializationContext) throws IOException, 
JsonProcessingException {
+            final JavaType propertiesType = 
deserializationContext.getConfig().getTypeFactory().constructMapType(HashMap.class,
 String.class, Object.class);
+
+            Object id = null;
+            String label = null;
+            Object outVId = null;
+            String outVLabel = null;
+            Object inVId = null;
+            String inVLabel = null;
+            Map<String, Object> properties = null;
+            while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+                if (jsonParser.getCurrentName().equals(GraphSONTokens.ID)) {
+                    jsonParser.nextToken();
+                    id = deserializationContext.readValue(jsonParser, 
Object.class);
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.LABEL)) {
+                    jsonParser.nextToken();
+                    label = jsonParser.getText();
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.OUT)) {
+                    jsonParser.nextToken();
+                    outVId = deserializationContext.readValue(jsonParser, 
Object.class);
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.OUT_LABEL)) {
+                    jsonParser.nextToken();
+                    outVLabel = jsonParser.getText();
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.IN)) {
+                    jsonParser.nextToken();
+                    inVId = deserializationContext.readValue(jsonParser, 
Object.class);
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.IN_LABEL)) {
+                    jsonParser.nextToken();
+                    inVLabel = jsonParser.getText();
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.PROPERTIES)) {
+                    jsonParser.nextToken();
+                    properties = deserializationContext.readValue(jsonParser, 
propertiesType);
+                }
+            }
+
+            return new DetachedEdge(id, label, properties, outVId, outVLabel, 
inVId, inVLabel);
+        }
+
+        @Override
+        public boolean isCachable() {
+            return true;
         }
     }
 
-    static class PropertyJacksonDeserializer extends 
AbstractObjectDeserializer<Property> {
+    static class PropertyJacksonDeserializer extends StdDeserializer<Property> 
{
 
         public PropertyJacksonDeserializer() {
             super(Property.class);
         }
 
         @Override
-        public Property createObject(final Map<String, Object> propData) {
-            return new DetachedProperty(
-                    (String) propData.get(GraphSONTokens.KEY),
-                    propData.get(GraphSONTokens.VALUE));
+        public Property deserialize(final JsonParser jsonParser, final 
DeserializationContext deserializationContext) throws IOException, 
JsonProcessingException {
+            String key = null;
+            Object value = null;
+            while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+                if (jsonParser.getCurrentName().equals(GraphSONTokens.KEY)) {
+                    jsonParser.nextToken();
+                    key = jsonParser.getText();
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.VALUE)) {
+                    jsonParser.nextToken();
+                    value = deserializationContext.readValue(jsonParser, 
Object.class);
+                }
+            }
+
+            return new DetachedProperty<>(key, value);
+        }
+
+        @Override
+        public boolean isCachable() {
+            return true;
         }
     }
 
@@ -485,20 +552,42 @@ class GraphSONSerializersV2d0 {
         }
     }
 
-    static class VertexPropertyJacksonDeserializer extends 
AbstractObjectDeserializer<VertexProperty> {
+    static class VertexPropertyJacksonDeserializer extends 
StdDeserializer<VertexProperty> {
 
         protected VertexPropertyJacksonDeserializer() {
             super(VertexProperty.class);
         }
 
         @Override
-        public VertexProperty createObject(final Map<String, Object> propData) 
{
-            return new DetachedVertexProperty(
-                    propData.get(GraphSONTokens.ID),
-                    (String) propData.get(GraphSONTokens.LABEL),
-                    propData.get(GraphSONTokens.VALUE),
-                    (Map) propData.get(GraphSONTokens.PROPERTIES)
-            );
+        public VertexProperty deserialize(final JsonParser jsonParser, final 
DeserializationContext deserializationContext) throws IOException, 
JsonProcessingException {
+            final JavaType propertiesType = 
deserializationContext.getConfig().getTypeFactory().constructMapType(HashMap.class,
 String.class, Object.class);
+
+            Object id = null;
+            String label = null;
+            Object value = null;
+            Map<String, Object> properties = null;
+            while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+                if (jsonParser.getCurrentName().equals(GraphSONTokens.ID)) {
+                    jsonParser.nextToken();
+                    id = deserializationContext.readValue(jsonParser, 
Object.class);
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.LABEL)) {
+                    jsonParser.nextToken();
+                    label = jsonParser.getText();
+                } else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.VALUE)) {
+                    jsonParser.nextToken();
+                    value = deserializationContext.readValue(jsonParser, 
Object.class);
+                }else if 
(jsonParser.getCurrentName().equals(GraphSONTokens.PROPERTIES)) {
+                    jsonParser.nextToken();
+                    properties = deserializationContext.readValue(jsonParser, 
propertiesType);
+                }
+            }
+
+            return new DetachedVertexProperty<>(id, label, value, properties);
+        }
+
+        @Override
+        public boolean isCachable() {
+            return true;
         }
     }
 
@@ -555,6 +644,11 @@ class GraphSONSerializersV2d0 {
             }
             return t;
         }
+
+        @Override
+        public boolean isCachable() {
+            return true;
+        }
     }
 
     static class IntegerJackonsDeserializer extends StdDeserializer<Integer> {
@@ -567,6 +661,11 @@ class GraphSONSerializersV2d0 {
         public Integer deserialize(JsonParser jsonParser, 
DeserializationContext deserializationContext) throws IOException, 
JsonProcessingException {
             return jsonParser.getIntValue();
         }
+
+        @Override
+        public boolean isCachable() {
+            return true;
+        }
     }
 
     static class DoubleJackonsDeserializer extends StdDeserializer<Double> {
@@ -579,6 +678,11 @@ class GraphSONSerializersV2d0 {
         public Double deserialize(JsonParser jsonParser, 
DeserializationContext deserializationContext) throws IOException, 
JsonProcessingException {
             return jsonParser.getDoubleValue();
         }
+
+        @Override
+        public boolean isCachable() {
+            return true;
+        }
     }
 }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/251f5b7e/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
----------------------------------------------------------------------
diff --git 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
index 394216b..280d1af 100644
--- 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
+++ 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
@@ -218,5 +218,10 @@ public final class TinkerIoRegistryV2d0 extends 
AbstractIoRegistry {
 
             return graph;
         }
+
+        @Override
+        public boolean isCachable() {
+            return true;
+        }
     }
 }

Reply via email to