diff --git a/benchmarks/src/jmh/java/io/grpc/netty/MethodDescriptorBenchmark.java b/benchmarks/src/jmh/java/io/grpc/netty/MethodDescriptorBenchmark.java new file mode 100644 index 00000000000..8ae3b41e74d --- /dev/null +++ b/benchmarks/src/jmh/java/io/grpc/netty/MethodDescriptorBenchmark.java @@ -0,0 +1,105 @@ +/* + * Copyright 2016, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.netty; + +import io.grpc.InternalKnownTransport; +import io.grpc.InternalMethodDescriptor; +import io.grpc.MethodDescriptor; +import io.netty.util.AsciiString; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.concurrent.TimeUnit; + +/** + * Benchmark for Method Descriptors. + */ +@State(Scope.Benchmark) +public class MethodDescriptorBenchmark { + + private static final MethodDescriptor.Marshaller marshaller = + new MethodDescriptor.Marshaller() { + @Override + public InputStream stream(Void value) { + return new ByteArrayInputStream(new byte[]{}); + } + + @Override + public Void parse(InputStream stream) { + return null; + } + }; + + MethodDescriptor method = MethodDescriptor.create( + MethodDescriptor.MethodType.UNARY, "Service/Method", marshaller, marshaller); + + InternalMethodDescriptor imd = new InternalMethodDescriptor(InternalKnownTransport.NETTY); + + byte[] directBytes = new AsciiString("/" + method.getFullMethodName()).toByteArray(); + + /** Foo bar. */ + @Benchmark + @BenchmarkMode(Mode.SampleTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public AsciiString old() { + return new AsciiString("/" + method.getFullMethodName()); + } + + /** Foo bar. */ + @Benchmark + @BenchmarkMode(Mode.SampleTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public AsciiString transportSpecific() { + AsciiString path; + if ((path = (AsciiString) imd.geRawMethodName(method)) != null) { + path = new AsciiString("/" + method.getFullMethodName()); + imd.setRawMethodName(method, path); + } + return path; + } + + /** Foo bar. */ + @Benchmark + @BenchmarkMode(Mode.SampleTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public AsciiString direct() { + return new AsciiString(directBytes, false); + } +} + diff --git a/core/src/main/java/io/grpc/InternalKnownTransport.java b/core/src/main/java/io/grpc/InternalKnownTransport.java new file mode 100644 index 00000000000..e765559de6e --- /dev/null +++ b/core/src/main/java/io/grpc/InternalKnownTransport.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc; + +/** + * All known transports. + */ +@Internal +public enum InternalKnownTransport { + NETTY, + ; +} + diff --git a/core/src/main/java/io/grpc/InternalMethodDescriptor.java b/core/src/main/java/io/grpc/InternalMethodDescriptor.java new file mode 100644 index 00000000000..3246742ddf9 --- /dev/null +++ b/core/src/main/java/io/grpc/InternalMethodDescriptor.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Accesses internal data. Do not use this. + */ +@Internal +public final class InternalMethodDescriptor { + private final InternalKnownTransport transport; + + public InternalMethodDescriptor(InternalKnownTransport transport) { + // TODO(carl-mastrangelo): maybe restrict access to this. + this.transport = checkNotNull(transport, "transport"); + } + + public Object geRawMethodName(MethodDescriptor md) { + return md.getRawMethodName(transport); + } + + public void setRawMethodName(MethodDescriptor md, Object o) { + md.setRawMethodName(transport, o); + } +} diff --git a/core/src/main/java/io/grpc/MethodDescriptor.java b/core/src/main/java/io/grpc/MethodDescriptor.java index 15347ea5c2c..2366ff8c535 100644 --- a/core/src/main/java/io/grpc/MethodDescriptor.java +++ b/core/src/main/java/io/grpc/MethodDescriptor.java @@ -34,6 +34,7 @@ import com.google.common.base.Preconditions; import java.io.InputStream; +import java.util.concurrent.atomic.AtomicReferenceArray; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -55,6 +56,17 @@ public class MethodDescriptor { private final Marshaller responseMarshaller; private final boolean idempotent; + private final AtomicReferenceArray rawMethodNames = + new AtomicReferenceArray(InternalKnownTransport.values().length); + + final Object getRawMethodName(InternalKnownTransport t) { + return rawMethodNames.get(t.ordinal()); + } + + final void setRawMethodName(InternalKnownTransport t, Object o) { + rawMethodNames.lazySet(t.ordinal(), o); + } + /** * The call type of a method. */ @@ -152,10 +164,11 @@ public static MethodDescriptor create type, fullMethodName, requestMarshaller, responseMarshaller, false); } - private MethodDescriptor(MethodType type, String fullMethodName, - Marshaller requestMarshaller, - Marshaller responseMarshaller, - boolean idempotent) { + private MethodDescriptor( + MethodType type, String fullMethodName, + Marshaller requestMarshaller, + Marshaller responseMarshaller, + boolean idempotent) { this.type = Preconditions.checkNotNull(type, "type"); this.fullMethodName = Preconditions.checkNotNull(fullMethodName, "fullMethodName"); this.requestMarshaller = Preconditions.checkNotNull(requestMarshaller, "requestMarshaller"); diff --git a/netty/src/main/java/io/grpc/netty/NettyClientStream.java b/netty/src/main/java/io/grpc/netty/NettyClientStream.java index 518029e4300..c6cefabb229 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientStream.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientStream.java @@ -35,6 +35,8 @@ import static com.google.common.base.Preconditions.checkState; import static io.netty.buffer.Unpooled.EMPTY_BUFFER; +import io.grpc.InternalKnownTransport; +import io.grpc.InternalMethodDescriptor; import io.grpc.Metadata; import io.grpc.MethodDescriptor; import io.grpc.Status; @@ -56,6 +58,10 @@ * Client stream for a Netty transport. */ abstract class NettyClientStream extends Http2ClientStream implements StreamIdHolder { + + private static final InternalMethodDescriptor methodDescriptorAccessor = + new InternalMethodDescriptor(InternalKnownTransport.NETTY); + private final MethodDescriptor method; /** {@code null} after start. */ private Metadata headers; @@ -94,7 +100,11 @@ public void start(ClientStreamListener listener) { super.start(listener); // Convert the headers into Netty HTTP/2 headers. - AsciiString defaultPath = new AsciiString("/" + method.getFullMethodName()); + AsciiString defaultPath = (AsciiString) methodDescriptorAccessor.geRawMethodName(method); + if (defaultPath == null) { + defaultPath = new AsciiString("/" + method.getFullMethodName()); + methodDescriptorAccessor.setRawMethodName(method, defaultPath); + } headers.removeAll(GrpcUtil.USER_AGENT_KEY); Http2Headers http2Headers = Utils.convertClientHeaders(headers, scheme, defaultPath, authority, userAgent);