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