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 <jorgebaygon...@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);
+    }
 }

Reply via email to