From 67cef441b21ffc900ad5fb112cbd43434d281760 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 5 Nov 2018 14:05:02 +0100 Subject: [PATCH] Support direct buffers in hpack (#3058) Signed-off-by: Greg Wilkins --- .../eclipse/jetty/http2/hpack/Huffman.java | 30 +--- .../eclipse/jetty/http2/hpack/HpackTest.java | 9 +- .../jetty/http2/hpack/HuffmanTest.java | 3 +- .../jetty/io/jmh/ByteBufferBenchmark.java | 154 ++++++++++++++++++ 4 files changed, 169 insertions(+), 27 deletions(-) create mode 100644 jetty-jmh/src/main/java/org/eclipse/jetty/io/jmh/ByteBufferBenchmark.java diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java index ddb2c4a97df..a0ed7b538e1 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java @@ -350,23 +350,16 @@ public class Huffman return decode(buffer,buffer.remaining()); } - public static String decode(ByteBuffer buffer,int length) throws HpackException.CompressionException + public static String decode(ByteBuffer buffer, int length) throws HpackException.CompressionException { StringBuilder out = new StringBuilder(length*2); int node = 0; int current = 0; int bits = 0; - byte[] array = buffer.array(); - int position=buffer.position(); - int start=buffer.arrayOffset()+position; - int end=start+length; - buffer.position(position+length); - - - for (int i=start; i= 8) @@ -460,10 +453,6 @@ public class Huffman { long current = 0; int n = 0; - - byte[] array = buffer.array(); - int p=buffer.arrayOffset()+buffer.position(); - int len = s.length(); for (int i=0;i= 8) { n -= 8; - array[p++]=(byte)(current >> n); + buffer.put((byte)(current >> n)); } } - if (n > 0) + if (n > 0) { - current <<= (8 - n); - current |= (0xFF >>> n); - array[p++]=(byte)current; + current <<= (8 - n); + current |= (0xFF >>> n); + buffer.put((byte)(current)); } - - buffer.position(p-buffer.arrayOffset()); + } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 355ffb2953f..5962fdfb65e 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -19,10 +19,9 @@ package org.eclipse.jetty.http2.hpack; import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; import java.nio.ByteBuffer; @@ -51,7 +50,7 @@ public class HpackTest { HpackEncoder encoder = new HpackEncoder(); HpackDecoder decoder = new HpackDecoder(4096,8192); - ByteBuffer buffer = BufferUtil.allocate(16*1024); + ByteBuffer buffer = BufferUtil.allocateDirect(16*1024); HttpFields fields0 = new HttpFields(); fields0.add(HttpHeader.CONTENT_TYPE,"text/html"); @@ -104,7 +103,7 @@ public class HpackTest { HpackEncoder encoder = new HpackEncoder(); HpackDecoder decoder = new HpackDecoder(4096,164); - ByteBuffer buffer = BufferUtil.allocate(16*1024); + ByteBuffer buffer = BufferUtil.allocateDirect(16*1024); HttpFields fields0 = new HttpFields(); fields0.add("1234567890","1234567890123456789012345678901234567890"); @@ -144,7 +143,7 @@ public class HpackTest { HpackEncoder encoder = new HpackEncoder(200,200); HpackDecoder decoder = new HpackDecoder(200,1024); - ByteBuffer buffer = BufferUtil.allocate(16*1024); + ByteBuffer buffer = BufferUtil.allocateDirect(16*1024); HttpFields fields0 = new HttpFields(); fields0.add("123456789012345678901234567890123456788901234567890","value"); diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java index bf7a935458c..c909d383d54 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.hpack; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.util.Locale; import java.util.stream.Stream; @@ -79,7 +80,7 @@ public class HuffmanTest assertThrows(IllegalArgumentException.class, () -> Huffman.octetsNeeded(s)); - assertThrows(IllegalArgumentException.class, + assertThrows(BufferOverflowException.class, () -> Huffman.encode(BufferUtil.allocate(32), s)); } } diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/io/jmh/ByteBufferBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/io/jmh/ByteBufferBenchmark.java new file mode 100644 index 00000000000..eb2ba3ec9b2 --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/io/jmh/ByteBufferBenchmark.java @@ -0,0 +1,154 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.io.jmh; + +import java.nio.ByteBuffer; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + + +@State(Scope.Benchmark) +@Threads(4) +@Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +public class ByteBufferBenchmark +{ + public long test(ByteBuffer buffer) + { + buffer.clear(); + while(buffer.hasRemaining()) + { + int size = ThreadLocalRandom.current().nextInt(1024); + byte[] bytes = new byte[size]; + ThreadLocalRandom.current().nextBytes(bytes); + buffer.put(bytes,0,Math.min(bytes.length,buffer.remaining())); + } + + buffer.flip(); + + long sum = 0; + while(buffer.hasRemaining()) + sum += buffer.get(); + + return sum; + } + + + public long testArray(ByteBuffer buffer) + { + buffer.clear(); + byte[] array = buffer.array(); + int offset = buffer.arrayOffset(); + int end = offset + buffer.remaining(); + while(offset