You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by jo...@apache.org on 2019/02/25 12:09:17 UTC

[tinkerpop] branch TINKERPOP-2166 created (now 543a0e2)

This is an automated email from the ASF dual-hosted git repository.

jorgebg pushed a change to branch TINKERPOP-2166
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git.


      at 543a0e2  TINKERPOP-2166 Cache expression to obtain the method in PSerializer

This branch includes the following new commits:

     new 543a0e2  TINKERPOP-2166 Cache expression to obtain the method in PSerializer

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[tinkerpop] 01/01: TINKERPOP-2166 Cache expression to obtain the method in PSerializer

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jorgebg pushed a commit to branch TINKERPOP-2166
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 543a0e222c5247e7d45d44b0803037f3be5c8acd
Author: Jorge Bay Gondra <jo...@gmail.com>
AuthorDate: Mon Feb 25 13:03:45 2019 +0100

    TINKERPOP-2166 Cache expression to obtain the method in PSerializer
---
 .../driver/ser/binary/types/PSerializer.java       | 133 +++++++++++++++------
 .../driver/GraphBinaryReaderWriterBenchmark.java   |   9 ++
 2 files changed, 108 insertions(+), 34 deletions(-)

diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/PSerializer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/PSerializer.java
index 0ae3420..b7c08a0 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/PSerializer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/binary/types/PSerializer.java
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
 
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -34,6 +35,8 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -42,6 +45,8 @@ public class PSerializer<T extends P> extends SimpleTypeSerializer<T> {
 
     private final Class<T> classOfP;
 
+    private final ConcurrentHashMap<PFunctionId, CheckedFunction> methods = new ConcurrentHashMap<>();
+
     public PSerializer(final DataType typeOfP, final Class<T> classOfP) {
         super(typeOfP);
         this.classOfP = classOfP;
@@ -53,59 +58,88 @@ public class PSerializer<T extends P> extends SimpleTypeSerializer<T> {
         final int length = context.readValue(buffer, Integer.class, false);
         final Object[] args = new Object[length];
         final Class<?>[] argumentClasses = new Class[length];
-        boolean collectionType = false;
         for (int i = 0; i < length; i++) {
             args[i] = context.read(buffer);
             argumentClasses[i] = args[i].getClass();
         }
 
-        switch (predicateName) {
-            case "and":
-                return (T) ((P) args[0]).and((P) args[1]);
-            case "or":
-                return (T) ((P) args[0]).or((P) args[1]);
-            default:
-                Method m;
+        if ("and".equals(predicateName)) {
+            return (T) ((P) args[0]).and((P) args[1]);
+        } else if ("or".equals(predicateName)) {
+            return (T) ((P) args[0]).or((P) args[1]);
+        }
+
+        CheckedFunction<Object[], T> f = getMethod(predicateName, argumentClasses);
+
+        try {
+            return f.apply(args);
+        } catch (Exception ex) {
+            throw new SerializationException(ex);
+        }
+    }
+
+    private CheckedFunction getMethod(final String predicateName, final Class<?>[] argumentClasses) throws SerializationException {
+        final PFunctionId id = new PFunctionId(predicateName, argumentClasses);
+
+        CheckedFunction<Object[], T> result = methods.get(id);
+
+        if (result == null) {
+            boolean collectionType = false;
+            Method m;
+            try {
+                // do a direct lookup
+                m = classOfP.getMethod(predicateName, argumentClasses);
+            } catch (NoSuchMethodException ex0) {
+                // then try collection types
                 try {
-                    // do a direct lookup
-                    m = classOfP.getMethod(predicateName, argumentClasses);
-                } catch (NoSuchMethodException ex0) {
-                    // then try collection types
+                    m = classOfP.getMethod(predicateName, Collection.class);
+                    collectionType = true;
+                } catch (NoSuchMethodException ex1) {
+                    // finally go for the generics
                     try {
-                        m = classOfP.getMethod(predicateName, Collection.class);
-                        collectionType = true;
-                    } catch (NoSuchMethodException ex1) {
-                        // finally go for the generics
-                        try {
-                            m = classOfP.getMethod(predicateName, Object.class);
-                        } catch (NoSuchMethodException ex2) {
-                            throw new SerializationException("not found");
-                        }
+                        m = classOfP.getMethod(predicateName, Object.class);
+                    } catch (NoSuchMethodException ex2) {
+                        throw new SerializationException("not found");
                     }
                 }
+            }
 
-                try {
-                    if (Modifier.isStatic(m.getModifiers())) {
-                        if (collectionType)
-                            return (T) m.invoke(null, Arrays.asList(args));
-                        else
-                            return (T) m.invoke(null, args);
+            final Method finalMethod = m;
+
+            try {
+                if (Modifier.isStatic(m.getModifiers())) {
+                    if (collectionType) {
+                        result = (args) -> (T) finalMethod.invoke(null, Arrays.asList(args));
                     } else {
-                        // try an instance method as it might be a form of ConnectiveP which means there is a P as an
-                        // argument that should be used as the object of an instance method
-                        if (args.length != 2 || !(args[0] instanceof P) || !(args[1] instanceof P))
+                        result = (args) -> (T) finalMethod.invoke(null, args);
+                    }
+                } else {
+                    // try an instance method as it might be a form of ConnectiveP which means there is a P as an
+                    // argument that should be used as the object of an instance method
+                    if (argumentClasses.length != 2) {
+                        throw new IllegalStateException(String.format("Could not determine the form of P for %s and %s",
+                                predicateName, Arrays.asList(argumentClasses)));
+                    }
+
+                    result = (args) -> {
+                        if (!(args[0] instanceof P) || !(args[1] instanceof P))
                             throw new IllegalStateException(String.format("Could not determine the form of P for %s and %s",
                                     predicateName, Arrays.asList(args)));
 
                         final P firstP = (P) args[0];
                         final P secondP = (P) args[1];
 
-                        return (T) m.invoke(firstP, secondP);
-                    }
-                } catch (Exception ex) {
-                    throw new SerializationException(ex);
+                        return (T) finalMethod.invoke(firstP, secondP);
+                    };
                 }
+
+                methods.put(id, result);
+            } catch (Exception ex) {
+                throw new SerializationException(ex);
+            }
         }
+
+        return result;
     }
 
     @Override
@@ -127,4 +161,35 @@ public class PSerializer<T extends P> extends SimpleTypeSerializer<T> {
             context.write(o, buffer);
         }
     }
+
+    @FunctionalInterface
+    interface CheckedFunction<A, R> {
+        R apply(A t) throws InvocationTargetException, IllegalAccessException;
+    }
+
+    class PFunctionId {
+        private final String predicateName;
+        private final Class<?>[] argumentClasses;
+
+        PFunctionId(final String predicateName, final Class<?>[] argumentClasses) {
+            this.predicateName = predicateName;
+            this.argumentClasses = argumentClasses;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            PFunctionId that = (PFunctionId) o;
+            return predicateName.equals(that.predicateName) &&
+                    Arrays.equals(argumentClasses, that.argumentClasses);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = Objects.hash(predicateName);
+            result = 31 * result + Arrays.hashCode(argumentClasses);
+            return result;
+        }
+    }
 }
diff --git a/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphBinaryReaderWriterBenchmark.java b/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphBinaryReaderWriterBenchmark.java
index 1cc509a..d0692b7 100644
--- a/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphBinaryReaderWriterBenchmark.java
+++ b/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphBinaryReaderWriterBenchmark.java
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
 import org.apache.tinkerpop.gremlin.driver.ser.binary.GraphBinaryReader;
 import org.apache.tinkerpop.gremlin.driver.ser.binary.GraphBinaryWriter;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.openjdk.jmh.annotations.Benchmark;
@@ -53,6 +54,7 @@ public class GraphBinaryReaderWriterBenchmark extends AbstractBenchmarkBase {
     public static class BenchmarkState {
         public ByteBuf bytecodeBuffer1 = allocator.buffer(2048);
         public ByteBuf bytecodeBuffer2 = allocator.buffer(2048);
+        public ByteBuf pBuffer1 = allocator.buffer(2048);
         public final Bytecode bytecode1 = new Bytecode();
 
         public ByteBuf bufferWrite = allocator.buffer(2048);
@@ -79,12 +81,14 @@ public class GraphBinaryReaderWriterBenchmark extends AbstractBenchmarkBase {
 
             writer.writeValue(bytecode1, bytecodeBuffer1, false);
             writer.writeValue(bytecode2, bytecodeBuffer2, false);
+            writer.writeValue(P.between(1, 2), pBuffer1, false);
         }
 
         @Setup(Level.Invocation)
         public void setupInvocation() {
             bytecodeBuffer1.readerIndex(0);
             bytecodeBuffer2.readerIndex(0);
+            pBuffer1.readerIndex(0);
             bufferWrite.readerIndex(0);
             bufferWrite.writerIndex(0);
         }
@@ -116,4 +120,9 @@ public class GraphBinaryReaderWriterBenchmark extends AbstractBenchmarkBase {
     public void readBytecode2(BenchmarkState state) throws SerializationException {
         reader.readValue(state.bytecodeBuffer2, Bytecode.class, false);
     }
+
+    @Benchmark
+    public void readP1(BenchmarkState state) throws SerializationException {
+        reader.readValue(state.pBuffer1, P.class, false);
+    }
 }