From 4ad2c75fbc6f4c979762e8ba229ac11da8761623 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 16 Jun 2022 10:00:53 +1000 Subject: [PATCH 01/24] Combined ByteBufferPool Signed-off-by: Greg Wilkins --- .../jetty/io/AbstractByteBufferPool.java | 42 +++++++++++++++---- .../eclipse/jetty/io/ArrayByteBufferPool.java | 36 ++++++++++++---- .../org/eclipse/jetty/io/ByteBufferPool.java | 7 +++- .../io/LogarithmicArrayByteBufferPool.java | 8 ++++ .../jetty/io/MappedByteBufferPool.java | 6 +-- .../jetty/io/RetainableByteBufferPool.java | 26 ++++++------ 6 files changed, 94 insertions(+), 31 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index 759935f4bda0..052e64827850 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -30,26 +30,49 @@ abstract class AbstractByteBufferPool implements ByteBufferPool { private final int _factor; - private final int _maxQueueLength; + private final int _maxCapacity; + private final int _maxBucketSize; private final long _maxHeapMemory; private final long _maxDirectMemory; private final AtomicLong _heapMemory = new AtomicLong(); private final AtomicLong _directMemory = new AtomicLong(); - + private final RetainableByteBufferPool _retainableByteBufferPool; + /** * Creates a new ByteBufferPool with the given configuration. * * @param factor the capacity factor - * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxBucketSize the maximum ByteBuffer queue length * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic + * @param retainedHeapMemory the max heap memory in bytes, -1 for no retained memory or 0 to use default heuristic + * @param retainedDirectMemory the max direct memory in bytes, -1 for no retained memory or 0 to use default heuristic */ - protected AbstractByteBufferPool(int factor, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) + protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { _factor = factor <= 0 ? 1024 : factor; - _maxQueueLength = maxQueueLength; + _maxCapacity = maxCapacity > 0 ? maxCapacity : 64 * 1024; + _maxBucketSize = maxBucketSize; _maxHeapMemory = (maxHeapMemory != 0) ? maxHeapMemory : Runtime.getRuntime().maxMemory() / 4; _maxDirectMemory = (maxDirectMemory != 0) ? maxDirectMemory : Runtime.getRuntime().maxMemory() / 4; + + if (retainedHeapMemory < 0 && retainedDirectMemory < 0) + _retainableByteBufferPool = RetainableByteBufferPool.from(this); + else + _retainableByteBufferPool = newRetainableByteBufferPool(maxCapacity, maxBucketSize, + (retainedHeapMemory != 0) ? retainedHeapMemory : _maxHeapMemory / 2, + (retainedDirectMemory != 0) ? retainedDirectMemory : _maxDirectMemory / 2); + } + + protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + { + return RetainableByteBufferPool.from(this); + } + + @Override + public RetainableByteBufferPool asRetainableByteBufferPool() + { + return _retainableByteBufferPool; } protected int getCapacityFactor() @@ -57,9 +80,14 @@ protected int getCapacityFactor() return _factor; } - protected int getMaxQueueLength() + protected int getMaxCapacity() + { + return _maxCapacity; + } + + protected int getMaxBucketSize() { - return _maxQueueLength; + return _maxBucketSize; } @Deprecated diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index 02a6130c9aee..0c55ea02f63c 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -90,19 +90,35 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max * @param minCapacity the minimum ByteBuffer capacity * @param factor the capacity factor * @param maxCapacity the maximum ByteBuffer capacity - * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxBucketSize the maximum ByteBuffer queue length in a {@link ByteBufferPool.Bucket} * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic */ - public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) + public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory) { - super(factor, maxQueueLength, maxHeapMemory, maxDirectMemory); + this(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, -1, -1); + } + + /** + * Creates a new ArrayByteBufferPool with the given configuration. + * + * @param minCapacity the minimum ByteBuffer capacity + * @param factor the capacity factor + * @param maxCapacity the maximum ByteBuffer capacity + * @param maxBucketSize the maximum ByteBuffer queue length in a {@link ByteBufferPool.Bucket} + * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic + * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic + * @param retainedHeapMemory the max heap memory in bytes, -1 for no retained memory or 0 to use default heuristic + * @param retainedDirectMemory the max direct memory in bytes, -1 for no retained memory or 0 to use default heuristic + */ + public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) + { + super(factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); + maxCapacity = getMaxCapacity(); factor = getCapacityFactor(); if (minCapacity <= 0) minCapacity = 0; - if (maxCapacity <= 0) - maxCapacity = 64 * 1024; if ((maxCapacity % factor) != 0 || factor >= maxCapacity) throw new IllegalArgumentException("The capacity factor must be a divisor of maxCapacity"); _maxCapacity = maxCapacity; @@ -119,6 +135,12 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max } } + @Override + protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + { + return new ArrayRetainableByteBufferPool(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); + } + @Override public ByteBuffer acquire(int size, boolean direct) { @@ -162,7 +184,7 @@ public void release(ByteBuffer buffer) private Bucket newBucket(int key, boolean direct) { - return new Bucket(capacityFor(key), getMaxQueueLength(), updateMemory(direct)); + return new Bucket(capacityFor(key), getMaxBucketSize(), updateMemory(direct)); } @Override @@ -286,7 +308,7 @@ public String toString() this.getClass().getSimpleName(), hashCode(), _minCapacity, _maxCapacity, - getMaxQueueLength(), + getMaxBucketSize(), getCapacityFactor()); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index 860503a5b9f6..340c4aed85c9 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -78,6 +78,11 @@ default ByteBuffer newByteBuffer(int capacity, boolean direct) return direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity); } + default RetainableByteBufferPool asRetainableByteBufferPool() + { + return RetainableByteBufferPool.from(this); + } + public static class Lease { private final ByteBufferPool byteBufferPool; @@ -148,7 +153,7 @@ public void release(ByteBuffer buffer) } } - public static class Bucket + class Bucket { private final Queue _queue = new ConcurrentLinkedQueue<>(); private final int _capacity; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java index d01e10cc8091..0a717573d772 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java @@ -66,6 +66,14 @@ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQ super(minCapacity, 1, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory); } + @Override + protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + { + return new ArrayRetainableByteBufferPool(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory, + c -> 32 - Integer.numberOfLeadingZeros(c - 1), + i -> 1 << i); + } + @Override protected int bucketFor(int capacity) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java index 9d3bebfa117b..59c86a1ac8c5 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java @@ -99,13 +99,13 @@ public MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket, long maxHeapMemory, long maxDirectMemory) { - super(factor, maxQueueLength, maxHeapMemory, maxDirectMemory); + super(factor, 0, maxQueueLength, maxHeapMemory, maxDirectMemory, -1, -1); _newBucket = newBucket; } private Bucket newBucket(int key, boolean direct) { - return (_newBucket != null) ? _newBucket.apply(key) : new Bucket(capacityFor(key), getMaxQueueLength(), updateMemory(direct)); + return (_newBucket != null) ? _newBucket.apply(key) : new Bucket(capacityFor(key), getMaxBucketSize(), updateMemory(direct)); } @Override @@ -269,7 +269,7 @@ public String toString() { return String.format("%s@%x{maxQueueLength=%s, factor=%s}", this.getClass().getSimpleName(), hashCode(), - getMaxQueueLength(), + getMaxBucketSize(), getCapacityFactor()); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java index 9cee4e72e69e..2492608b214e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java @@ -36,23 +36,23 @@ public interface RetainableByteBufferPool * Finds a {@link RetainableByteBufferPool} implementation in the given container, or wrap the given * {@link ByteBufferPool} with an adapter. * @param container the container to search for an existing memory pool. - * @param byteBufferPool the {@link ByteBufferPool} to wrap if no memory pool was found in the container. - * @return the {@link RetainableByteBufferPool} found or the wrapped one. + * @param byteBufferPool Use {@link ByteBufferPool#asRetainableByteBufferPool()} to convert if no memory pool was found in the container. + * @return the {@link RetainableByteBufferPool} found or the converted one. */ static RetainableByteBufferPool findOrAdapt(Container container, ByteBufferPool byteBufferPool) { RetainableByteBufferPool retainableByteBufferPool = container == null ? null : container.getBean(RetainableByteBufferPool.class); - if (retainableByteBufferPool == null) + return retainableByteBufferPool == null ? byteBufferPool.asRetainableByteBufferPool() : retainableByteBufferPool; + } + + static RetainableByteBufferPool from(ByteBufferPool byteBufferPool) + { + return (size, direct) -> { - // Wrap the ByteBufferPool instance. - retainableByteBufferPool = (size, direct) -> - { - ByteBuffer byteBuffer = byteBufferPool.acquire(size, direct); - RetainableByteBuffer retainableByteBuffer = new RetainableByteBuffer(byteBuffer, byteBufferPool::release); - retainableByteBuffer.acquire(); - return retainableByteBuffer; - }; - } - return retainableByteBufferPool; + ByteBuffer byteBuffer = byteBufferPool.acquire(size, direct); + RetainableByteBuffer retainableByteBuffer = new RetainableByteBuffer(byteBuffer, byteBufferPool::release); + retainableByteBuffer.acquire(); + return retainableByteBuffer; + }; } } From 6d7dfa1f5c2a69ca785ce2e607324a70f2f9fd8b Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 16 Jun 2022 10:10:55 +1000 Subject: [PATCH 02/24] Combined ByteBufferPool Retained pool acquires from outer pool Signed-off-by: Greg Wilkins --- .../eclipse/jetty/io/ArrayByteBufferPool.java | 15 ++++++++++++++- .../jetty/io/ArrayRetainableByteBufferPool.java | 12 +++++++++++- .../io/LogarithmicArrayByteBufferPool.java | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index 0c55ea02f63c..a312a5daf995 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -138,7 +138,20 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max @Override protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) { - return new ArrayRetainableByteBufferPool(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); + return new ArrayRetainableByteBufferPool(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory) + { + @Override + protected ByteBuffer allocate(int capacity) + { + return ArrayByteBufferPool.this.acquire(capacity, false); + } + + @Override + protected ByteBuffer allocateDirect(int capacity) + { + return ArrayByteBufferPool.this.acquire(capacity, true); + } + }; } @Override diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java index cf4c0e239bf4..82e7d2eb738a 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java @@ -191,9 +191,19 @@ public RetainableByteBuffer acquire(int size, boolean direct) return buffer; } + protected ByteBuffer allocate(int capacity) + { + return ByteBuffer.allocate(capacity); + } + + protected ByteBuffer allocateDirect(int capacity) + { + return ByteBuffer.allocateDirect(capacity); + } + private RetainableByteBuffer newRetainableByteBuffer(int capacity, boolean direct, Consumer releaser) { - ByteBuffer buffer = direct ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); + ByteBuffer buffer = direct ? allocateDirect(capacity) : allocate(capacity); BufferUtil.clear(buffer); RetainableByteBuffer retainableByteBuffer = new RetainableByteBuffer(buffer, releaser); retainableByteBuffer.acquire(); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java index 0a717573d772..a6707288811e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java @@ -13,6 +13,8 @@ package org.eclipse.jetty.io; +import java.nio.ByteBuffer; + /** * Extension of the {@link ArrayByteBufferPool} whose bucket sizes increase exponentially instead of linearly. * Each bucket will be double the size of the previous bucket, this decreases the amounts of buckets required @@ -71,7 +73,20 @@ protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, { return new ArrayRetainableByteBufferPool(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory, c -> 32 - Integer.numberOfLeadingZeros(c - 1), - i -> 1 << i); + i -> 1 << i) + { + @Override + protected ByteBuffer allocate(int capacity) + { + return LogarithmicArrayByteBufferPool.this.acquire(capacity, false); + } + + @Override + protected ByteBuffer allocateDirect(int capacity) + { + return LogarithmicArrayByteBufferPool.this.acquire(capacity, true); + } + }; } @Override From 72beab122345b58fb1f977530136bf876e428181 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 16 Jun 2022 12:50:32 +1000 Subject: [PATCH 03/24] Combined ByteBufferPool updated modules and xml Signed-off-by: Greg Wilkins --- .../org/eclipse/jetty/io/AbstractByteBufferPool.java | 4 ++-- .../config/etc/jetty-bytebufferpool-logarithmic.xml | 2 ++ .../src/main/config/etc/jetty-bytebufferpool.xml | 2 ++ .../main/config/modules/bytebufferpool-logarithmic.mod | 10 ++++++++-- .../src/main/config/modules/bytebufferpool.mod | 10 ++++++++-- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index 052e64827850..bb15e73c0968 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -60,8 +60,8 @@ protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, _retainableByteBufferPool = RetainableByteBufferPool.from(this); else _retainableByteBufferPool = newRetainableByteBufferPool(maxCapacity, maxBucketSize, - (retainedHeapMemory != 0) ? retainedHeapMemory : _maxHeapMemory / 2, - (retainedDirectMemory != 0) ? retainedDirectMemory : _maxDirectMemory / 2); + (retainedHeapMemory != 0) ? retainedHeapMemory : Runtime.getRuntime().maxMemory() / 4, + (retainedDirectMemory != 0) ? retainedDirectMemory : Runtime.getRuntime().maxMemory() / 4); } protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) diff --git a/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml b/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml index 5c31db102477..4d1fb5039321 100644 --- a/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml +++ b/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml @@ -7,5 +7,7 @@ + + diff --git a/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml b/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml index 4e8d2402d91e..d9004974f0c5 100644 --- a/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml +++ b/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml @@ -8,5 +8,7 @@ + + diff --git a/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod b/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod index 77f816c9bbd6..2243cda0916b 100644 --- a/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod +++ b/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod @@ -23,8 +23,14 @@ etc/jetty-bytebufferpool-logarithmic.xml ## Maximum queue length for each bucket (-1 for unbounded) #jetty.byteBufferPool.maxQueueLength=-1 -## Maximum heap memory retainable by the pool (0 for heuristic, -1 for unlimited) +## Maximum heap memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxHeapMemory=0 -## Maximum direct memory retainable by the pool (0 for heuristic, -1 for unlimited) +## Maximum direct memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxDirectMemory=0 + +## Maximum heap memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +#jetty.byteBufferPool.retainedHeapMemory=0 + +## Maximum direct memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +#jetty.byteBufferPool.retainedDirectMemory=0 diff --git a/jetty-server/src/main/config/modules/bytebufferpool.mod b/jetty-server/src/main/config/modules/bytebufferpool.mod index ba95298e2d10..1992935035da 100644 --- a/jetty-server/src/main/config/modules/bytebufferpool.mod +++ b/jetty-server/src/main/config/modules/bytebufferpool.mod @@ -24,8 +24,14 @@ etc/jetty-bytebufferpool.xml ## Maximum queue length for each bucket (-1 for unbounded). #jetty.byteBufferPool.maxQueueLength=-1 -## Maximum heap memory retainable by the pool (0 for heuristic, -1 for unlimited). +## Maximum heap memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxHeapMemory=0 -## Maximum direct memory retainable by the pool (0 for heuristic, -1 for unlimited). +## Maximum direct memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxDirectMemory=0 + +## Maximum heap memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +#jetty.byteBufferPool.retainedHeapMemory=0 + +## Maximum direct memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +#jetty.byteBufferPool.retainedDirectMemory=0 \ No newline at end of file From a66f6f21f093e0864676fd7f6f74bf21e8c54755 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 16 Jun 2022 17:23:27 +1000 Subject: [PATCH 04/24] Combined ByteBufferPool don't make a private pool Signed-off-by: Greg Wilkins --- .../main/java/org/eclipse/jetty/server/AbstractConnector.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 9ea4af80201d..393115c4c44a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -32,7 +32,6 @@ import java.util.stream.Collectors; import org.eclipse.jetty.io.ArrayByteBufferPool; -import org.eclipse.jetty.io.ArrayRetainableByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.RetainableByteBufferPool; @@ -192,7 +191,7 @@ public AbstractConnector( _byteBufferPool = pool != null ? pool : new ArrayByteBufferPool(); addBean(_byteBufferPool); RetainableByteBufferPool retainableByteBufferPool = _server.getBean(RetainableByteBufferPool.class); - addBean(retainableByteBufferPool == null ? new ArrayRetainableByteBufferPool() : retainableByteBufferPool, retainableByteBufferPool == null); + addBean(retainableByteBufferPool == null ? _byteBufferPool.asRetainableByteBufferPool() : retainableByteBufferPool, retainableByteBufferPool == null); addEventListener(new Container.Listener() { From 60871f8a369bdd9b6160cc416efeae2f1cffabfe Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 16 Jun 2022 18:55:26 +1000 Subject: [PATCH 05/24] Combined ByteBufferPool improved dump Signed-off-by: Greg Wilkins --- .../eclipse/jetty/io/ArrayByteBufferPool.java | 38 ++++++++------ .../io/ArrayRetainableByteBufferPool.java | 52 +++++++++---------- .../jetty/io/RetainableByteBufferPool.java | 20 +++++-- .../jetty/server/AbstractConnector.java | 5 +- 4 files changed, 65 insertions(+), 50 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index a312a5daf995..e547d2e96c61 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -96,7 +96,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory) { - this(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, -1, -1); + this(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, 0, 0); } /** @@ -138,20 +138,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max @Override protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) { - return new ArrayRetainableByteBufferPool(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory) - { - @Override - protected ByteBuffer allocate(int capacity) - { - return ArrayByteBufferPool.this.acquire(capacity, false); - } - - @Override - protected ByteBuffer allocateDirect(int capacity) - { - return ArrayByteBufferPool.this.acquire(capacity, true); - } - }; + return new Retained(maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); } @Override @@ -311,6 +298,7 @@ public void dump(Appendable out, String indent) throws IOException dump.add("Indirect Buckets size=" + indirect.size()); dump.add("Direct Buckets size=" + direct.size()); } + dump.add(asRetainableByteBufferPool()); Dumpable.dumpObjects(out, indent, this, dump); } @@ -324,4 +312,24 @@ public String toString() getMaxBucketSize(), getCapacityFactor()); } + + private class Retained extends ArrayRetainableByteBufferPool + { + Retained(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + { + super(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); + } + + @Override + protected ByteBuffer allocate(int capacity) + { + return ArrayByteBufferPool.this.acquire(capacity, false); + } + + @Override + protected ByteBuffer allocateDirect(int capacity) + { + return ArrayByteBufferPool.this.acquire(capacity, true); + } + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java index 82e7d2eb738a..7b9edb8900ee 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java @@ -44,8 +44,8 @@ public class ArrayRetainableByteBufferPool implements RetainableByteBufferPool, { private static final Logger LOG = LoggerFactory.getLogger(ArrayRetainableByteBufferPool.class); - private final Bucket[] _direct; - private final Bucket[] _indirect; + private final RetainedBucket[] _direct; + private final RetainedBucket[] _indirect; private final int _minCapacity; private final int _maxCapacity; private final long _maxHeapMemory; @@ -122,13 +122,13 @@ protected ArrayRetainableByteBufferPool(int minCapacity, int factor, int maxCapa bucketCapacity = i -> (i + 1) * f; int length = bucketIndexFor.apply(maxCapacity) + 1; - Bucket[] directArray = new Bucket[length]; - Bucket[] indirectArray = new Bucket[length]; + RetainedBucket[] directArray = new RetainedBucket[length]; + RetainedBucket[] indirectArray = new RetainedBucket[length]; for (int i = 0; i < directArray.length; i++) { int capacity = Math.min(bucketCapacity.apply(i), maxCapacity); - directArray[i] = new Bucket(capacity, maxBucketSize); - indirectArray[i] = new Bucket(capacity, maxBucketSize); + directArray[i] = new RetainedBucket(capacity, maxBucketSize); + indirectArray[i] = new RetainedBucket(capacity, maxBucketSize); } _minCapacity = minCapacity; @@ -155,15 +155,15 @@ public int getMaxCapacity() @Override public RetainableByteBuffer acquire(int size, boolean direct) { - Bucket bucket = bucketFor(size, direct); + RetainedBucket bucket = bucketFor(size, direct); if (bucket == null) return newRetainableByteBuffer(size, direct, byteBuffer -> {}); - Bucket.Entry entry = bucket.acquire(); + RetainedBucket.Entry entry = bucket.acquire(); RetainableByteBuffer buffer; if (entry == null) { - Bucket.Entry reservedEntry = bucket.reserve(); + RetainedBucket.Entry reservedEntry = bucket.reserve(); if (reservedEntry != null) { buffer = newRetainableByteBuffer(bucket._capacity, direct, byteBuffer -> @@ -215,12 +215,12 @@ protected Pool poolFor(int capacity, boolean direct) return bucketFor(capacity, direct); } - private Bucket bucketFor(int capacity, boolean direct) + private RetainedBucket bucketFor(int capacity, boolean direct) { if (capacity < _minCapacity) return null; int idx = _bucketIndexFor.apply(capacity); - Bucket[] buckets = direct ? _direct : _indirect; + RetainedBucket[] buckets = direct ? _direct : _indirect; if (idx >= buckets.length) return null; return buckets[idx]; @@ -240,8 +240,8 @@ public long getHeapByteBufferCount() private long getByteBufferCount(boolean direct) { - Bucket[] buckets = direct ? _direct : _indirect; - return Arrays.stream(buckets).mapToLong(Bucket::size).sum(); + RetainedBucket[] buckets = direct ? _direct : _indirect; + return Arrays.stream(buckets).mapToLong(RetainedBucket::size).sum(); } @ManagedAttribute("The number of pooled direct ByteBuffers that are available") @@ -258,7 +258,7 @@ public long getAvailableHeapByteBufferCount() private long getAvailableByteBufferCount(boolean direct) { - Bucket[] buckets = direct ? _direct : _indirect; + RetainedBucket[] buckets = direct ? _direct : _indirect; return Arrays.stream(buckets).mapToLong(bucket -> bucket.values().stream().filter(Pool.Entry::isIdle).count()).sum(); } @@ -296,9 +296,9 @@ public long getAvailableHeapMemory() private long getAvailableMemory(boolean direct) { - Bucket[] buckets = direct ? _direct : _indirect; + RetainedBucket[] buckets = direct ? _direct : _indirect; long total = 0L; - for (Bucket bucket : buckets) + for (RetainedBucket bucket : buckets) { int capacity = bucket._capacity; total += bucket.values().stream().filter(Pool.Entry::isIdle).count() * capacity; @@ -313,11 +313,11 @@ public void clear() clearArray(_indirect, _currentHeapMemory); } - private void clearArray(Bucket[] poolArray, AtomicLong memoryCounter) + private void clearArray(RetainedBucket[] poolArray, AtomicLong memoryCounter) { - for (Bucket pool : poolArray) + for (RetainedBucket pool : poolArray) { - for (Bucket.Entry entry : pool.values()) + for (RetainedBucket.Entry entry : pool.values()) { entry.remove(); memoryCounter.addAndGet(-entry.getPooled().capacity()); @@ -348,13 +348,13 @@ private void evict(boolean direct, long excess) long now = System.nanoTime(); long totalClearedCapacity = 0L; - Bucket[] buckets = direct ? _direct : _indirect; + RetainedBucket[] buckets = direct ? _direct : _indirect; while (totalClearedCapacity < excess) { - for (Bucket bucket : buckets) + for (RetainedBucket bucket : buckets) { - Bucket.Entry oldestEntry = findOldestEntry(now, bucket); + RetainedBucket.Entry oldestEntry = findOldestEntry(now, bucket); if (oldestEntry == null) continue; @@ -399,8 +399,8 @@ public void dump(Appendable out, String indent) throws IOException private Pool.Entry findOldestEntry(long now, Pool bucket) { - Bucket.Entry oldestEntry = null; - for (Bucket.Entry entry : bucket.values()) + RetainedBucket.Entry oldestEntry = null; + for (RetainedBucket.Entry entry : bucket.values()) { if (oldestEntry != null) { @@ -416,11 +416,11 @@ private Pool.Entry findOldestEntry(long now, Pool + private static class RetainedBucket extends Pool { private final int _capacity; - Bucket(int capacity, int size) + RetainedBucket(int capacity, int size) { super(Pool.StrategyType.THREAD_ID, size, true); _capacity = capacity; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java index 2492608b214e..ec827cd1fc90 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java @@ -47,12 +47,22 @@ static RetainableByteBufferPool findOrAdapt(Container container, ByteBufferPool static RetainableByteBufferPool from(ByteBufferPool byteBufferPool) { - return (size, direct) -> + return new RetainableByteBufferPool() { - ByteBuffer byteBuffer = byteBufferPool.acquire(size, direct); - RetainableByteBuffer retainableByteBuffer = new RetainableByteBuffer(byteBuffer, byteBufferPool::release); - retainableByteBuffer.acquire(); - return retainableByteBuffer; + @Override + public RetainableByteBuffer acquire(int size, boolean direct) + { + ByteBuffer byteBuffer = byteBufferPool.acquire(size, direct); + RetainableByteBuffer retainableByteBuffer = new RetainableByteBuffer(byteBuffer, byteBufferPool::release); + retainableByteBuffer.acquire(); + return retainableByteBuffer; + } + + @Override + public String toString() + { + return String.format("NonRetainableByteBufferPool@%x{%s}", hashCode(), byteBufferPool.toString()); + } }; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 393115c4c44a..7cb8437c591f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -34,7 +34,6 @@ import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.RetainableByteBufferPool; import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.StringUtil; @@ -189,9 +188,7 @@ public AbstractConnector( if (pool == null) pool = _server.getBean(ByteBufferPool.class); _byteBufferPool = pool != null ? pool : new ArrayByteBufferPool(); - addBean(_byteBufferPool); - RetainableByteBufferPool retainableByteBufferPool = _server.getBean(RetainableByteBufferPool.class); - addBean(retainableByteBufferPool == null ? _byteBufferPool.asRetainableByteBufferPool() : retainableByteBufferPool, retainableByteBufferPool == null); + addBean(_byteBufferPool, pool == null); addEventListener(new Container.Listener() { From ca452709a00ace601c53a16c757deead5cc871c9 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 20 Jun 2022 11:38:58 +1000 Subject: [PATCH 06/24] Combined ByteBufferPool release retained buffers when removed Signed-off-by: Greg Wilkins --- .../jetty/io/AbstractByteBufferPool.java | 6 ++--- .../eclipse/jetty/io/ArrayByteBufferPool.java | 16 ++++++++---- .../io/ArrayRetainableByteBufferPool.java | 25 +++++++++++++------ .../org/eclipse/jetty/io/ByteBufferPool.java | 11 +++++--- .../jetty/io/LeakTrackingByteBufferPool.java | 7 ++++++ .../io/LogarithmicArrayByteBufferPool.java | 23 ----------------- .../jetty/io/RetainableByteBuffer.java | 6 ++--- .../jetty/io/RetainableByteBufferPool.java | 7 +++++- 8 files changed, 55 insertions(+), 46 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index bb15e73c0968..722c9063fbe9 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -51,7 +51,7 @@ abstract class AbstractByteBufferPool implements ByteBufferPool protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { _factor = factor <= 0 ? 1024 : factor; - _maxCapacity = maxCapacity > 0 ? maxCapacity : 64 * 1024; + _maxCapacity = maxCapacity > 0 ? maxCapacity : 64 * _factor; _maxBucketSize = maxBucketSize; _maxHeapMemory = (maxHeapMemory != 0) ? maxHeapMemory : Runtime.getRuntime().maxMemory() / 4; _maxDirectMemory = (maxDirectMemory != 0) ? maxDirectMemory : Runtime.getRuntime().maxMemory() / 4; @@ -59,12 +59,12 @@ protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, if (retainedHeapMemory < 0 && retainedDirectMemory < 0) _retainableByteBufferPool = RetainableByteBufferPool.from(this); else - _retainableByteBufferPool = newRetainableByteBufferPool(maxCapacity, maxBucketSize, + _retainableByteBufferPool = newRetainableByteBufferPool(factor, maxCapacity, maxBucketSize, (retainedHeapMemory != 0) ? retainedHeapMemory : Runtime.getRuntime().maxMemory() / 4, (retainedDirectMemory != 0) ? retainedDirectMemory : Runtime.getRuntime().maxMemory() / 4); } - protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) { return RetainableByteBufferPool.from(this); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index e547d2e96c61..b093ea0f991e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -136,9 +136,9 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max } @Override - protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) { - return new Retained(maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); + return new Retained(factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); } @Override @@ -313,11 +313,11 @@ public String toString() getCapacityFactor()); } - private class Retained extends ArrayRetainableByteBufferPool + protected class Retained extends ArrayRetainableByteBufferPool { - Retained(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + Retained(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) { - super(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); + super(0, factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); } @Override @@ -331,5 +331,11 @@ protected ByteBuffer allocateDirect(int capacity) { return ArrayByteBufferPool.this.acquire(capacity, true); } + + @Override + protected void removed(RetainableByteBuffer retainedBuffer) + { + ArrayByteBufferPool.this.release(retainedBuffer.getBuffer()); + } } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java index 7b9edb8900ee..53193e84727d 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java @@ -39,6 +39,7 @@ * The {@code maxHeapMemory} and {@code maxDirectMemory} default heuristic is to use {@link Runtime#maxMemory()} * divided by 4.

*/ +@SuppressWarnings("resource") @ManagedObject public class ArrayRetainableByteBufferPool implements RetainableByteBufferPool, Dumpable { @@ -114,7 +115,7 @@ protected ArrayRetainableByteBufferPool(int minCapacity, int factor, int maxCapa int f = factor <= 0 ? 1024 : factor; if ((maxCapacity % f) != 0 || f >= maxCapacity) - throw new IllegalArgumentException("The capacity factor must be a divisor of maxCapacity"); + throw new IllegalArgumentException(String.format("The capacity factor(%d) must be a divisor of maxCapacity(%d)", f, maxCapacity)); if (bucketIndexFor == null) bucketIndexFor = c -> (c - 1) / f; @@ -157,7 +158,7 @@ public RetainableByteBuffer acquire(int size, boolean direct) { RetainedBucket bucket = bucketFor(size, direct); if (bucket == null) - return newRetainableByteBuffer(size, direct, byteBuffer -> {}); + return newRetainableByteBuffer(size, direct, this::removed); RetainedBucket.Entry entry = bucket.acquire(); RetainableByteBuffer buffer; @@ -166,9 +167,9 @@ public RetainableByteBuffer acquire(int size, boolean direct) RetainedBucket.Entry reservedEntry = bucket.reserve(); if (reservedEntry != null) { - buffer = newRetainableByteBuffer(bucket._capacity, direct, byteBuffer -> + buffer = newRetainableByteBuffer(bucket._capacity, direct, retainedBuffer -> { - BufferUtil.reset(byteBuffer); + BufferUtil.reset(retainedBuffer.getBuffer()); reservedEntry.release(); }); reservedEntry.enable(buffer, true); @@ -180,7 +181,7 @@ public RetainableByteBuffer acquire(int size, boolean direct) } else { - buffer = newRetainableByteBuffer(size, direct, byteBuffer -> {}); + buffer = newRetainableByteBuffer(size, direct, this::removed); } } else @@ -201,7 +202,11 @@ protected ByteBuffer allocateDirect(int capacity) return ByteBuffer.allocateDirect(capacity); } - private RetainableByteBuffer newRetainableByteBuffer(int capacity, boolean direct, Consumer releaser) + protected void removed(RetainableByteBuffer retainedBuffer) + { + } + + private RetainableByteBuffer newRetainableByteBuffer(int capacity, boolean direct, Consumer releaser) { ByteBuffer buffer = direct ? allocateDirect(capacity) : allocate(capacity); BufferUtil.clear(buffer); @@ -319,8 +324,11 @@ private void clearArray(RetainedBucket[] poolArray, AtomicLong memoryCounter) { for (RetainedBucket.Entry entry : pool.values()) { - entry.remove(); - memoryCounter.addAndGet(-entry.getPooled().capacity()); + if (entry.remove()) + { + memoryCounter.addAndGet(-entry.getPooled().capacity()); + removed(entry.getPooled()); + } } } } @@ -366,6 +374,7 @@ private void evict(boolean direct, long excess) else _currentHeapMemory.addAndGet(-clearedCapacity); totalClearedCapacity += clearedCapacity; + removed(oldestEntry.getPooled()); } // else a concurrent thread evicted the same entry -> do not account for its capacity. } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index 340c4aed85c9..d2325537cbeb 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -43,7 +43,7 @@ public interface ByteBufferPool * @return the requested buffer * @see #release(ByteBuffer) */ - public ByteBuffer acquire(int size, boolean direct); + ByteBuffer acquire(int size, boolean direct); /** *

Returns a {@link ByteBuffer}, usually obtained with {@link #acquire(int, boolean)} @@ -52,7 +52,7 @@ public interface ByteBufferPool * @param buffer the buffer to return * @see #acquire(int, boolean) */ - public void release(ByteBuffer buffer); + void release(ByteBuffer buffer); /** *

Removes a {@link ByteBuffer} that was previously obtained with {@link #acquire(int, boolean)}.

@@ -78,12 +78,17 @@ default ByteBuffer newByteBuffer(int capacity, boolean direct) return direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity); } + /** + * Get this pool as a {@link RetainableByteBufferPool}, which supports reference counting of the + * buffers and possibly a more efficient lookup mechanism based on the {@link org.eclipse.jetty.util.Pool} class. + * @return This pool wrapped as a RetainableByteBufferPool. + */ default RetainableByteBufferPool asRetainableByteBufferPool() { return RetainableByteBufferPool.from(this); } - public static class Lease + class Lease { private final ByteBufferPool byteBufferPool; private final List buffers; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java index 0c2adbef2452..07a430e22da3 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java @@ -58,6 +58,13 @@ public LeakTrackingByteBufferPool(ByteBufferPool delegate) addBean(delegate); } + @Override + public RetainableByteBufferPool asRetainableByteBufferPool() + { + // the retainable pool is just a client of the normal pool, so no special handling required. + return delegate.asRetainableByteBufferPool(); + } + @Override public ByteBuffer acquire(int size, boolean direct) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java index a6707288811e..d01e10cc8091 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java @@ -13,8 +13,6 @@ package org.eclipse.jetty.io; -import java.nio.ByteBuffer; - /** * Extension of the {@link ArrayByteBufferPool} whose bucket sizes increase exponentially instead of linearly. * Each bucket will be double the size of the previous bucket, this decreases the amounts of buckets required @@ -68,27 +66,6 @@ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQ super(minCapacity, 1, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory); } - @Override - protected RetainableByteBufferPool newRetainableByteBufferPool(int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) - { - return new ArrayRetainableByteBufferPool(0, -1, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory, - c -> 32 - Integer.numberOfLeadingZeros(c - 1), - i -> 1 << i) - { - @Override - protected ByteBuffer allocate(int capacity) - { - return LogarithmicArrayByteBufferPool.this.acquire(capacity, false); - } - - @Override - protected ByteBuffer allocateDirect(int capacity) - { - return LogarithmicArrayByteBufferPool.this.acquire(capacity, true); - } - }; - } - @Override protected int bucketFor(int capacity) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBuffer.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBuffer.java index 2599940d34ea..84156df40154 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBuffer.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBuffer.java @@ -37,10 +37,10 @@ public class RetainableByteBuffer implements Retainable { private final ByteBuffer buffer; private final AtomicInteger references = new AtomicInteger(); - private final Consumer releaser; + private final Consumer releaser; private final AtomicLong lastUpdate = new AtomicLong(System.nanoTime()); - RetainableByteBuffer(ByteBuffer buffer, Consumer releaser) + RetainableByteBuffer(ByteBuffer buffer, Consumer releaser) { this.releaser = releaser; this.buffer = buffer; @@ -112,7 +112,7 @@ public boolean release() if (ref == 0) { lastUpdate.setOpaque(System.nanoTime()); - releaser.accept(buffer); + releaser.accept(this); return true; } return false; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java index ec827cd1fc90..91f921e750eb 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java @@ -53,11 +53,16 @@ static RetainableByteBufferPool from(ByteBufferPool byteBufferPool) public RetainableByteBuffer acquire(int size, boolean direct) { ByteBuffer byteBuffer = byteBufferPool.acquire(size, direct); - RetainableByteBuffer retainableByteBuffer = new RetainableByteBuffer(byteBuffer, byteBufferPool::release); + RetainableByteBuffer retainableByteBuffer = new RetainableByteBuffer(byteBuffer, this::release); retainableByteBuffer.acquire(); return retainableByteBuffer; } + private void release(RetainableByteBuffer retainedBuffer) + { + byteBufferPool.release(retainedBuffer.getBuffer()); + } + @Override public String toString() { From 12625834538039f67cb189627a532401f7d4947a Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 20 Jun 2022 11:43:28 +1000 Subject: [PATCH 07/24] Combined ByteBufferPool Move Bucket out of interface into abstract pool Signed-off-by: Greg Wilkins --- .../jetty/io/AbstractByteBufferPool.java | 96 ++++++++++++++++++ .../eclipse/jetty/io/ArrayByteBufferPool.java | 20 ++-- .../org/eclipse/jetty/io/ByteBufferPool.java | 97 ------------------- .../jetty/io/ArrayByteBufferPoolTest.java | 24 ++--- .../jetty/io/MappedByteBufferPoolTest.java | 2 +- 5 files changed, 119 insertions(+), 120 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index 722c9063fbe9..1f6987c8c5d9 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -14,10 +14,15 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; +import java.util.Objects; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.IntConsumer; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; @@ -151,6 +156,97 @@ public long getMemory(boolean direct) return memory.get(); } + protected static class Bucket + { + private final Queue _queue = new ConcurrentLinkedQueue<>(); + private final int _capacity; + private final int _maxSize; + private final AtomicInteger _size; + private final AtomicLong _lastUpdate = new AtomicLong(System.nanoTime()); + private final IntConsumer _memoryFunction; + + @Deprecated + public Bucket(int capacity, int maxSize) + { + this(capacity, maxSize, i -> {}); + } + + public Bucket(int capacity, int maxSize, IntConsumer memoryFunction) + { + _capacity = capacity; + _maxSize = maxSize; + _size = maxSize > 0 ? new AtomicInteger() : null; + _memoryFunction = Objects.requireNonNull(memoryFunction); + } + + public ByteBuffer acquire() + { + ByteBuffer buffer = _queue.poll(); + if (buffer != null) + { + if (_size != null) + _size.decrementAndGet(); + _memoryFunction.accept(-buffer.capacity()); + } + + return buffer; + } + + public void release(ByteBuffer buffer) + { + resetUpdateTime(); + BufferUtil.reset(buffer); + if (_size == null || _size.incrementAndGet() <= _maxSize) + { + _queue.offer(buffer); + _memoryFunction.accept(buffer.capacity()); + } + else + { + _size.decrementAndGet(); + } + } + + void resetUpdateTime() + { + _lastUpdate.lazySet(System.nanoTime()); + } + + public void clear() + { + int size = _size == null ? 0 : _size.get() - 1; + while (size >= 0) + { + ByteBuffer buffer = acquire(); + if (buffer == null) + break; + if (_size != null) + --size; + } + } + + boolean isEmpty() + { + return _queue.isEmpty(); + } + + int size() + { + return _queue.size(); + } + + long getLastUpdate() + { + return _lastUpdate.getOpaque(); + } + + @Override + public String toString() + { + return String.format("%s@%x{capacity=%d, size=%d, maxSize=%d}", getClass().getSimpleName(), hashCode(), _capacity, size(), _maxSize); + } + } + IntConsumer updateMemory(boolean direct) { return (direct) ? _directMemory::addAndGet : _heapMemory::addAndGet; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index b093ea0f991e..16836a548cd3 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -44,8 +44,8 @@ public class ArrayByteBufferPool extends AbstractByteBufferPool implements Dumpa private final int _maxCapacity; private final int _minCapacity; - private final ByteBufferPool.Bucket[] _direct; - private final ByteBufferPool.Bucket[] _indirect; + private final Bucket[] _direct; + private final Bucket[] _indirect; private boolean _detailedDump = false; /** @@ -90,7 +90,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max * @param minCapacity the minimum ByteBuffer capacity * @param factor the capacity factor * @param maxCapacity the maximum ByteBuffer capacity - * @param maxBucketSize the maximum ByteBuffer queue length in a {@link ByteBufferPool.Bucket} + * @param maxBucketSize the maximum ByteBuffer queue length in a {@link Bucket} * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic */ @@ -105,7 +105,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max * @param minCapacity the minimum ByteBuffer capacity * @param factor the capacity factor * @param maxCapacity the maximum ByteBuffer capacity - * @param maxBucketSize the maximum ByteBuffer queue length in a {@link ByteBufferPool.Bucket} + * @param maxBucketSize the maximum ByteBuffer queue length in a {@link Bucket} * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic * @param retainedHeapMemory the max heap memory in bytes, -1 for no retained memory or 0 to use default heuristic @@ -126,8 +126,8 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max // Initialize all buckets in constructor and never modify the array again. int length = bucketFor(maxCapacity) + 1; - _direct = new ByteBufferPool.Bucket[length]; - _indirect = new ByteBufferPool.Bucket[length]; + _direct = new Bucket[length]; + _indirect = new Bucket[length]; for (int i = 0; i < length; i++) { _direct[i] = newBucket(i, true); @@ -145,7 +145,7 @@ protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int m public ByteBuffer acquire(int size, boolean direct) { int capacity = size < _minCapacity ? size : capacityFor(bucketFor(size)); - ByteBufferPool.Bucket bucket = bucketFor(size, direct); + Bucket bucket = bucketFor(size, direct); if (bucket == null) return newByteBuffer(capacity, direct); ByteBuffer buffer = bucket.acquire(); @@ -174,7 +174,7 @@ public void release(ByteBuffer buffer) return; boolean direct = buffer.isDirect(); - ByteBufferPool.Bucket bucket = bucketFor(capacity, direct); + Bucket bucket = bucketFor(capacity, direct); if (bucket != null) { bucket.release(buffer); @@ -232,7 +232,7 @@ protected int capacityFor(int bucket) return bucket * getCapacityFactor(); } - private ByteBufferPool.Bucket bucketFor(int capacity, boolean direct) + private Bucket bucketFor(int capacity, boolean direct) { if (capacity < _minCapacity) return null; @@ -264,7 +264,7 @@ private long getByteBufferCount(boolean direct) } // Package local for testing - ByteBufferPool.Bucket[] bucketsFor(boolean direct) + Bucket[] bucketsFor(boolean direct) { return direct ? _direct : _indirect; } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index d2325537cbeb..285548458795 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -16,12 +16,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.IntConsumer; import org.eclipse.jetty.util.BufferUtil; @@ -157,95 +151,4 @@ public void release(ByteBuffer buffer) byteBufferPool.release(buffer); } } - - class Bucket - { - private final Queue _queue = new ConcurrentLinkedQueue<>(); - private final int _capacity; - private final int _maxSize; - private final AtomicInteger _size; - private final AtomicLong _lastUpdate = new AtomicLong(System.nanoTime()); - private final IntConsumer _memoryFunction; - - @Deprecated - public Bucket(int capacity, int maxSize) - { - this(capacity, maxSize, i -> {}); - } - - public Bucket(int capacity, int maxSize, IntConsumer memoryFunction) - { - _capacity = capacity; - _maxSize = maxSize; - _size = maxSize > 0 ? new AtomicInteger() : null; - _memoryFunction = Objects.requireNonNull(memoryFunction); - } - - public ByteBuffer acquire() - { - ByteBuffer buffer = _queue.poll(); - if (buffer != null) - { - if (_size != null) - _size.decrementAndGet(); - _memoryFunction.accept(-buffer.capacity()); - } - - return buffer; - } - - public void release(ByteBuffer buffer) - { - resetUpdateTime(); - BufferUtil.reset(buffer); - if (_size == null || _size.incrementAndGet() <= _maxSize) - { - _queue.offer(buffer); - _memoryFunction.accept(buffer.capacity()); - } - else - { - _size.decrementAndGet(); - } - } - - void resetUpdateTime() - { - _lastUpdate.lazySet(System.nanoTime()); - } - - public void clear() - { - int size = _size == null ? 0 : _size.get() - 1; - while (size >= 0) - { - ByteBuffer buffer = acquire(); - if (buffer == null) - break; - if (_size != null) - --size; - } - } - - boolean isEmpty() - { - return _queue.isEmpty(); - } - - int size() - { - return _queue.size(); - } - - long getLastUpdate() - { - return _lastUpdate.getOpaque(); - } - - @Override - public String toString() - { - return String.format("%s@%x{capacity=%d, size=%d, maxSize=%d}", getClass().getSimpleName(), hashCode(), _capacity, size(), _maxSize); - } - } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java index 2c66f9f559ae..528e28cccfb0 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java @@ -18,7 +18,7 @@ import java.util.Arrays; import java.util.Objects; -import org.eclipse.jetty.io.ByteBufferPool.Bucket; +import org.eclipse.jetty.io.AbstractByteBufferPool.Bucket; import org.eclipse.jetty.util.StringUtil; import org.junit.jupiter.api.Test; @@ -37,7 +37,7 @@ public class ArrayByteBufferPoolTest public void testMinimumRelease() { ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000); - ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + Bucket[] buckets = bufferPool.bucketsFor(true); for (int size = 1; size <= 9; size++) { @@ -45,7 +45,7 @@ public void testMinimumRelease() assertTrue(buffer.isDirect()); assertEquals(size, buffer.capacity()); - for (ByteBufferPool.Bucket bucket : buckets) + for (Bucket bucket : buckets) { if (bucket != null) assertTrue(bucket.isEmpty()); @@ -53,7 +53,7 @@ public void testMinimumRelease() bufferPool.release(buffer); - for (ByteBufferPool.Bucket bucket : buckets) + for (Bucket bucket : buckets) { if (bucket != null) assertTrue(bucket.isEmpty()); @@ -68,7 +68,7 @@ public void testMaxRelease() int factor = 1; int maxCapacity = 1024; ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(minCapacity, factor, maxCapacity); - ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + Bucket[] buckets = bufferPool.bucketsFor(true); for (int size = maxCapacity - 1; size <= maxCapacity + 1; size++) { @@ -77,7 +77,7 @@ public void testMaxRelease() assertTrue(buffer.isDirect()); assertThat(buffer.capacity(), greaterThanOrEqualTo(size)); - for (ByteBufferPool.Bucket bucket : buckets) + for (Bucket bucket : buckets) { if (bucket != null) assertTrue(bucket.isEmpty()); @@ -87,7 +87,7 @@ public void testMaxRelease() int pooled = Arrays.stream(buckets) .filter(Objects::nonNull) - .mapToInt(Bucket::size) + .mapToInt(AbstractByteBufferPool.Bucket::size) .sum(); if (size <= maxCapacity) @@ -101,7 +101,7 @@ public void testMaxRelease() public void testAcquireRelease() { ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000); - ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + Bucket[] buckets = bufferPool.bucketsFor(true); for (int size = 390; size <= 510; size++) { @@ -110,7 +110,7 @@ public void testAcquireRelease() assertTrue(buffer.isDirect()); assertThat(buffer.capacity(), greaterThanOrEqualTo(size)); - for (ByteBufferPool.Bucket bucket : buckets) + for (Bucket bucket : buckets) { if (bucket != null) assertTrue(bucket.isEmpty()); @@ -120,7 +120,7 @@ public void testAcquireRelease() int pooled = Arrays.stream(buckets) .filter(Objects::nonNull) - .mapToInt(Bucket::size) + .mapToInt(AbstractByteBufferPool.Bucket::size) .sum(); assertEquals(1, pooled); } @@ -130,7 +130,7 @@ public void testAcquireRelease() public void testAcquireReleaseAcquire() { ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000); - ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + Bucket[] buckets = bufferPool.bucketsFor(true); for (int size = 390; size <= 510; size++) { @@ -144,7 +144,7 @@ public void testAcquireReleaseAcquire() int pooled = Arrays.stream(buckets) .filter(Objects::nonNull) - .mapToInt(Bucket::size) + .mapToInt(AbstractByteBufferPool.Bucket::size) .sum(); assertEquals(1, pooled); diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java index e5020b1aa600..1b4f1ae7d3f7 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java @@ -16,7 +16,7 @@ import java.nio.ByteBuffer; import java.util.concurrent.ConcurrentMap; -import org.eclipse.jetty.io.ByteBufferPool.Bucket; +import org.eclipse.jetty.io.AbstractByteBufferPool.Bucket; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.junit.jupiter.api.Test; From f1ffc83a0cce0b3e036569399053921341b205e4 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 21 Jun 2022 11:28:23 +1000 Subject: [PATCH 08/24] Combined ByteBufferPool Updates from review. removed findOrAdapt removed default asRetainableByteBuffer Signed-off-by: Greg Wilkins --- .../client/http/HttpReceiverOverHTTP.java | 2 +- .../client/http/HttpConnectionOverFCGI.java | 2 +- .../fcgi/server/ServerFCGIConnection.java | 2 +- .../client/HTTP2ClientConnectionFactory.java | 2 +- .../AbstractHTTP2ServerConnectionFactory.java | 2 +- .../http3/internal/HTTP3StreamConnection.java | 2 +- .../eclipse/jetty/io/ArrayByteBufferPool.java | 2 +- .../org/eclipse/jetty/io/ByteBufferPool.java | 7 ++----- .../io/LogarithmicArrayByteBufferPool.java | 18 +++++++++++++++++- .../eclipse/jetty/io/NullByteBufferPool.java | 8 ++++++++ .../jetty/io/RetainableByteBufferPool.java | 15 --------------- .../eclipse/jetty/io/ssl/SslConnection.java | 2 +- .../jetty/server/AbstractConnector.java | 4 +++- .../eclipse/jetty/server/HttpConnection.java | 2 +- .../jetty/server/SslConnectionFactory.java | 2 +- .../eclipse/jetty/server/HttpOutputTest.java | 16 ++-------------- .../core/client/CoreClientUpgradeRequest.java | 2 +- .../server/internal/RFC6455Handshaker.java | 2 +- .../server/internal/RFC8441Handshaker.java | 2 +- 19 files changed, 45 insertions(+), 49 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index b54115ea365d..5440a0401ad7 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -64,7 +64,7 @@ public HttpReceiverOverHTTP(HttpChannelOverHTTP channel) parser.setHeaderCacheCaseSensitive(httpTransport.isHeaderCacheCaseSensitive()); } - this.retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(httpClient, httpClient.getByteBufferPool()); + this.retainableByteBufferPool = httpClient.getByteBufferPool().asRetainableByteBufferPool(); } @Override diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java index 796483ef5ff5..2d59fee72b16 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java @@ -79,7 +79,7 @@ public HttpConnectionOverFCGI(EndPoint endPoint, HttpDestination destination, Pr this.parser = new ClientParser(new ResponseListener()); requests.addLast(0); HttpClient client = destination.getHttpClient(); - this.networkByteBufferPool = RetainableByteBufferPool.findOrAdapt(client, client.getByteBufferPool()); + this.networkByteBufferPool = client.getByteBufferPool().asRetainableByteBufferPool(); } public HttpDestination getHttpDestination() diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java index 8c31d1e0a527..e60a1b18bfb1 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java @@ -50,7 +50,7 @@ public ServerFCGIConnection(Connector connector, EndPoint endPoint, HttpConfigur { super(endPoint, connector.getExecutor()); this.connector = connector; - this.networkByteBufferPool = RetainableByteBufferPool.findOrAdapt(connector, connector.getByteBufferPool()); + this.networkByteBufferPool = connector.getByteBufferPool().asRetainableByteBufferPool(); this.flusher = new Flusher(endPoint); this.configuration = configuration; this.sendStatus200 = sendStatus200; diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index d8ac8861dd4f..01609b09fbc0 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -68,7 +68,7 @@ public Connection newConnection(EndPoint endPoint, Map context) parser.setMaxFrameLength(client.getMaxFrameLength()); parser.setMaxSettingsKeys(client.getMaxSettingsKeys()); - RetainableByteBufferPool retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(client, byteBufferPool); + RetainableByteBufferPool retainableByteBufferPool = byteBufferPool.asRetainableByteBufferPool(); HTTP2ClientConnection connection = new HTTP2ClientConnection(client, retainableByteBufferPool, executor, endPoint, parser, session, client.getInputBufferSize(), promise, listener); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index ae180edf9e12..60937d5bdc65 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -280,7 +280,7 @@ public Connection newConnection(Connector connector, EndPoint endPoint) parser.setMaxFrameLength(getMaxFrameLength()); parser.setMaxSettingsKeys(getMaxSettingsKeys()); - RetainableByteBufferPool retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(connector, connector.getByteBufferPool()); + RetainableByteBufferPool retainableByteBufferPool = connector.getByteBufferPool().asRetainableByteBufferPool(); HTTP2Connection connection = new HTTP2ServerConnection(retainableByteBufferPool, connector.getExecutor(), endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener); diff --git a/jetty-http3/http3-common/src/main/java/org/eclipse/jetty/http3/internal/HTTP3StreamConnection.java b/jetty-http3/http3-common/src/main/java/org/eclipse/jetty/http3/internal/HTTP3StreamConnection.java index d7d3de5e3df7..4cbe3e530792 100644 --- a/jetty-http3/http3-common/src/main/java/org/eclipse/jetty/http3/internal/HTTP3StreamConnection.java +++ b/jetty-http3/http3-common/src/main/java/org/eclipse/jetty/http3/internal/HTTP3StreamConnection.java @@ -57,7 +57,7 @@ public abstract class HTTP3StreamConnection extends AbstractConnection public HTTP3StreamConnection(QuicStreamEndPoint endPoint, Executor executor, ByteBufferPool byteBufferPool, MessageParser parser) { super(endPoint, executor); - this.buffers = RetainableByteBufferPool.findOrAdapt(null, byteBufferPool); + this.buffers = byteBufferPool.asRetainableByteBufferPool(); this.parser = parser; parser.init(MessageListener::new); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index f73229aa5131..81549ec0981c 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -96,7 +96,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory) { - this(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, 0, 0); + this(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, -1, -1); } /** diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index 285548458795..e6433a843d19 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -75,12 +75,9 @@ default ByteBuffer newByteBuffer(int capacity, boolean direct) /** * Get this pool as a {@link RetainableByteBufferPool}, which supports reference counting of the * buffers and possibly a more efficient lookup mechanism based on the {@link org.eclipse.jetty.util.Pool} class. - * @return This pool wrapped as a RetainableByteBufferPool. + * @return This pool as a RetainableByteBufferPool. The same instance is always returned by multiple calls to this method. */ - default RetainableByteBufferPool asRetainableByteBufferPool() - { - return RetainableByteBufferPool.from(this); - } + RetainableByteBufferPool asRetainableByteBufferPool(); class Lease { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java index d01e10cc8091..d78710959112 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java @@ -63,7 +63,23 @@ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQ */ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) { - super(minCapacity, 1, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory); + this(minCapacity, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory, -1, -1); + } + + /** + * Creates a new ByteBufferPool with the given configuration. + * + * @param minCapacity the minimum ByteBuffer capacity + * @param maxCapacity the maximum ByteBuffer capacity + * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxHeapMemory the max heap memory in bytes + * @param maxDirectMemory the max direct memory in bytes + * @param retainedHeapMemory the max heap memory in bytes, -1 for no retained memory or 0 to use default heuristic + * @param retainedDirectMemory the max direct memory in bytes, -1 for no retained memory or 0 to use default heuristic + */ + public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) + { + super(minCapacity, 1, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); } @Override diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java index 217e658aae2b..88ab24651f68 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java @@ -19,6 +19,8 @@ public class NullByteBufferPool implements ByteBufferPool { + private RetainableByteBufferPool _retainableByteBufferPool = RetainableByteBufferPool.from(this); + @Override public ByteBuffer acquire(int size, boolean direct) { @@ -33,4 +35,10 @@ public void release(ByteBuffer buffer) { BufferUtil.clear(buffer); } + + @Override + public RetainableByteBufferPool asRetainableByteBufferPool() + { + return _retainableByteBufferPool; + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java index 91f921e750eb..0831bb636c84 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java @@ -15,8 +15,6 @@ import java.nio.ByteBuffer; -import org.eclipse.jetty.util.component.Container; - /** *

A {@link RetainableByteBuffer} pool.

*

Acquired buffers must be released by calling {@link RetainableByteBuffer#release()} otherwise the memory they hold will @@ -32,19 +30,6 @@ public interface RetainableByteBufferPool */ RetainableByteBuffer acquire(int size, boolean direct); - /** - * Finds a {@link RetainableByteBufferPool} implementation in the given container, or wrap the given - * {@link ByteBufferPool} with an adapter. - * @param container the container to search for an existing memory pool. - * @param byteBufferPool Use {@link ByteBufferPool#asRetainableByteBufferPool()} to convert if no memory pool was found in the container. - * @return the {@link RetainableByteBufferPool} found or the converted one. - */ - static RetainableByteBufferPool findOrAdapt(Container container, ByteBufferPool byteBufferPool) - { - RetainableByteBufferPool retainableByteBufferPool = container == null ? null : container.getBean(RetainableByteBufferPool.class); - return retainableByteBufferPool == null ? byteBufferPool.asRetainableByteBufferPool() : retainableByteBufferPool; - } - static RetainableByteBufferPool from(ByteBufferPool byteBufferPool) { return new RetainableByteBufferPool() diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 62214a1f866a..a0767bd0ab55 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -173,7 +173,7 @@ public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine, boolean useDirectBuffersForEncryption, boolean useDirectBuffersForDecryption) { - this(RetainableByteBufferPool.findOrAdapt(null, byteBufferPool), byteBufferPool, executor, endPoint, sslEngine, useDirectBuffersForEncryption, useDirectBuffersForDecryption); + this(byteBufferPool.asRetainableByteBufferPool(), byteBufferPool, executor, endPoint, sslEngine, useDirectBuffersForEncryption, useDirectBuffersForDecryption); } public SslConnection(RetainableByteBufferPool retainableByteBufferPool, ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine, diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 7cb8437c591f..d69d9c9d39ed 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -187,7 +187,9 @@ public AbstractConnector( addBean(_scheduler); if (pool == null) pool = _server.getBean(ByteBufferPool.class); - _byteBufferPool = pool != null ? pool : new ArrayByteBufferPool(); + + // TODO improve this + _byteBufferPool = pool != null ? pool : new ArrayByteBufferPool(-1, -1, -1, -1, -1, -1, 0, 0); addBean(_byteBufferPool, pool == null); addEventListener(new Container.Listener() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index aaf11cf501c8..23bf34db3d1c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -97,7 +97,7 @@ public HttpConnection(HttpConfiguration config, Connector connector, EndPoint en _config = config; _connector = connector; _bufferPool = _connector.getByteBufferPool(); - _retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(connector, _bufferPool); + _retainableByteBufferPool = _bufferPool.asRetainableByteBufferPool(); _generator = newHttpGenerator(); _channel = newHttpChannel(); _input = _channel.getRequest().getHttpInput(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java index 0d44be120c35..5b351cbd805d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java @@ -168,7 +168,7 @@ public Connection newConnection(Connector connector, EndPoint endPoint) protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine) { ByteBufferPool byteBufferPool = connector.getByteBufferPool(); - RetainableByteBufferPool retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(connector, byteBufferPool); + RetainableByteBufferPool retainableByteBufferPool = byteBufferPool.asRetainableByteBufferPool(); return new SslConnection(retainableByteBufferPool, byteBufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption()); } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java index 340d53158f30..ce8e8c0beec2 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java @@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.NullByteBufferPool; import org.eclipse.jetty.server.HttpOutput.Interceptor; import org.eclipse.jetty.server.LocalConnector.LocalEndPoint; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -69,19 +69,7 @@ public void init() throws Exception { _server = new Server(); - _server.addBean(new ByteBufferPool() - { - @Override - public ByteBuffer acquire(int size, boolean direct) - { - return direct ? BufferUtil.allocateDirect(size) : BufferUtil.allocate(size); - } - - @Override - public void release(ByteBuffer buffer) - { - } - }); + _server.addBean(new NullByteBufferPool()); HttpConnectionFactory http = new HttpConnectionFactory(); http.getHttpConfiguration().setRequestHeaderSize(1024); diff --git a/jetty-websocket/websocket-core-client/src/main/java/org/eclipse/jetty/websocket/core/client/CoreClientUpgradeRequest.java b/jetty-websocket/websocket-core-client/src/main/java/org/eclipse/jetty/websocket/core/client/CoreClientUpgradeRequest.java index 2008c5b91f83..3255bec5c074 100644 --- a/jetty-websocket/websocket-core-client/src/main/java/org/eclipse/jetty/websocket/core/client/CoreClientUpgradeRequest.java +++ b/jetty-websocket/websocket-core-client/src/main/java/org/eclipse/jetty/websocket/core/client/CoreClientUpgradeRequest.java @@ -440,7 +440,7 @@ else if (values.length == 1) HttpClient httpClient = wsClient.getHttpClient(); ByteBufferPool bufferPool = wsClient.getWebSocketComponents().getBufferPool(); - RetainableByteBufferPool retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(wsClient.getWebSocketComponents(), bufferPool); + RetainableByteBufferPool retainableByteBufferPool = bufferPool.asRetainableByteBufferPool(); WebSocketConnection wsConnection = new WebSocketConnection(endPoint, httpClient.getExecutor(), httpClient.getScheduler(), bufferPool, retainableByteBufferPool, coreSession); wsClient.getEventListeners().forEach(wsConnection::addEventListener); coreSession.setWebSocketConnection(wsConnection); diff --git a/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java b/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java index bca2538a1c3a..60af7246031a 100644 --- a/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java +++ b/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java @@ -97,7 +97,7 @@ protected WebSocketConnection createWebSocketConnection(Request baseRequest, Web HttpChannel httpChannel = baseRequest.getHttpChannel(); Connector connector = httpChannel.getConnector(); ByteBufferPool byteBufferPool = connector.getByteBufferPool(); - RetainableByteBufferPool retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(connector, byteBufferPool); + RetainableByteBufferPool retainableByteBufferPool = byteBufferPool.asRetainableByteBufferPool(); return newWebSocketConnection(httpChannel.getEndPoint(), connector.getExecutor(), connector.getScheduler(), byteBufferPool, retainableByteBufferPool, coreSession); } diff --git a/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC8441Handshaker.java b/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC8441Handshaker.java index 83c79d5bd9e3..4aebf3fa3461 100644 --- a/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC8441Handshaker.java +++ b/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC8441Handshaker.java @@ -81,7 +81,7 @@ protected WebSocketConnection createWebSocketConnection(Request baseRequest, Web Connector connector = httpChannel.getConnector(); EndPoint endPoint = httpChannel.getTunnellingEndPoint(); ByteBufferPool byteBufferPool = connector.getByteBufferPool(); - RetainableByteBufferPool retainableByteBufferPool = RetainableByteBufferPool.findOrAdapt(connector, byteBufferPool); + RetainableByteBufferPool retainableByteBufferPool = byteBufferPool.asRetainableByteBufferPool(); return newWebSocketConnection(endPoint, connector.getExecutor(), connector.getScheduler(), byteBufferPool, retainableByteBufferPool, coreSession); } From 417baf26449fcdbe1a7f88b9eb4848ffbd840fe3 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 28 Jun 2022 10:29:02 +1000 Subject: [PATCH 09/24] cleanup defaults Signed-off-by: Greg Wilkins --- .../jetty/io/AbstractByteBufferPool.java | 34 +++++++++++------ .../eclipse/jetty/io/ArrayByteBufferPool.java | 6 +-- .../io/LogarithmicArrayByteBufferPool.java | 6 +-- .../jetty/io/MappedByteBufferPool.java | 38 +++++++++++++++++-- .../jetty/io/MappedByteBufferPoolTest.java | 2 +- .../main/config/modules/bytebufferpool.mod | 1 + .../jetty/server/AbstractConnector.java | 25 ++++++++++-- 7 files changed, 86 insertions(+), 26 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index 1f6987c8c5d9..c3efeb337dd3 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -50,23 +50,35 @@ abstract class AbstractByteBufferPool implements ByteBufferPool * @param maxBucketSize the maximum ByteBuffer queue length * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic - * @param retainedHeapMemory the max heap memory in bytes, -1 for no retained memory or 0 to use default heuristic - * @param retainedDirectMemory the max direct memory in bytes, -1 for no retained memory or 0 to use default heuristic + * @param retainedHeapMemory the max heap memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic + * @param retainedDirectMemory the max direct memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic */ protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { _factor = factor <= 0 ? 1024 : factor; _maxCapacity = maxCapacity > 0 ? maxCapacity : 64 * _factor; _maxBucketSize = maxBucketSize; - _maxHeapMemory = (maxHeapMemory != 0) ? maxHeapMemory : Runtime.getRuntime().maxMemory() / 4; - _maxDirectMemory = (maxDirectMemory != 0) ? maxDirectMemory : Runtime.getRuntime().maxMemory() / 4; - - if (retainedHeapMemory < 0 && retainedDirectMemory < 0) - _retainableByteBufferPool = RetainableByteBufferPool.from(this); - else - _retainableByteBufferPool = newRetainableByteBufferPool(factor, maxCapacity, maxBucketSize, - (retainedHeapMemory != 0) ? retainedHeapMemory : Runtime.getRuntime().maxMemory() / 4, - (retainedDirectMemory != 0) ? retainedDirectMemory : Runtime.getRuntime().maxMemory() / 4); + _maxHeapMemory = memorySize(maxHeapMemory); + _maxDirectMemory = memorySize(maxDirectMemory); + _retainableByteBufferPool = (retainedHeapMemory == -2 && retainedDirectMemory == -2) + ? RetainableByteBufferPool.from(this) + : newRetainableByteBufferPool(factor, maxCapacity, maxBucketSize, retainedSize(retainedHeapMemory), retainedSize(retainedDirectMemory)); + } + + private static long retainedSize(long size) + { + if (size == -2) + return 0; + return memorySize(size); + } + + private static long memorySize(long size) + { + if (size < 0) + return -1; + if (size == 0) + return Runtime.getRuntime().maxMemory() / 4; + return size; } protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index 81549ec0981c..1b52c7be2607 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -96,7 +96,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory) { - this(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, -1, -1); + this(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, maxHeapMemory, maxDirectMemory); } /** @@ -108,8 +108,8 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int max * @param maxBucketSize the maximum ByteBuffer queue length in a {@link Bucket} * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic - * @param retainedHeapMemory the max heap memory in bytes, -1 for no retained memory or 0 to use default heuristic - * @param retainedDirectMemory the max direct memory in bytes, -1 for no retained memory or 0 to use default heuristic + * @param retainedHeapMemory the max heap memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic + * @param retainedDirectMemory the max direct memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java index d78710959112..db586a0ae4b0 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java @@ -63,7 +63,7 @@ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQ */ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) { - this(minCapacity, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory, -1, -1); + this(minCapacity, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory, maxHeapMemory, maxDirectMemory); } /** @@ -74,8 +74,8 @@ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQ * @param maxQueueLength the maximum ByteBuffer queue length * @param maxHeapMemory the max heap memory in bytes * @param maxDirectMemory the max direct memory in bytes - * @param retainedHeapMemory the max heap memory in bytes, -1 for no retained memory or 0 to use default heuristic - * @param retainedDirectMemory the max direct memory in bytes, -1 for no retained memory or 0 to use default heuristic + * @param retainedHeapMemory the max heap memory in bytes, -1 for unlimited retained memory or 0 to use default heuristic + * @param retainedDirectMemory the max direct memory in bytes, -1 for unlimited retained memory or 0 to use default heuristic */ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java index 59c86a1ac8c5..4ac8f482e568 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java @@ -83,11 +83,39 @@ public MappedByteBufferPool(int factor, int maxQueueLength) * @param maxQueueLength the maximum ByteBuffer queue length * @param newBucket the function that creates a Bucket */ - public MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket) + private MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket) { - this(factor, maxQueueLength, newBucket, 0, 0); + this(factor, maxQueueLength, newBucket, -1, -1, -1, -1); } + /** + * Creates a new MappedByteBufferPool with the given configuration. + * + * @param factor the capacity factor + * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic. + * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic. + */ + public MappedByteBufferPool(int factor, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) + { + this(factor, maxQueueLength, null, maxHeapMemory, maxDirectMemory, maxHeapMemory, maxDirectMemory); + } + + /** + * Creates a new MappedByteBufferPool with the given configuration. + * + * @param factor the capacity factor + * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic. + * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic. + * @param retainedHeapMemory the max heap memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic + * @param retainedDirectMemory the max direct memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic + */ + public MappedByteBufferPool(int factor, int maxQueueLength, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) + { + this(factor, maxQueueLength, null, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); + } + /** * Creates a new MappedByteBufferPool with the given configuration. * @@ -96,10 +124,12 @@ public MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket, long maxHeapMemory, long maxDirectMemory) + private MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { - super(factor, 0, maxQueueLength, maxHeapMemory, maxDirectMemory, -1, -1); + super(factor, 0, maxQueueLength, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); _newBucket = newBucket; } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java index 1b4f1ae7d3f7..8fec072dc3d3 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java @@ -138,7 +138,7 @@ public void testMaxMemory() { int factor = 1024; int maxMemory = 11 * factor; - MappedByteBufferPool bufferPool = new MappedByteBufferPool(factor, -1, null, -1, maxMemory); + MappedByteBufferPool bufferPool = new MappedByteBufferPool(factor, -1, -1, maxMemory); ConcurrentMap buckets = bufferPool.bucketsFor(true); // Create the buckets - the oldest is the larger. diff --git a/jetty-server/src/main/config/modules/bytebufferpool.mod b/jetty-server/src/main/config/modules/bytebufferpool.mod index 1992935035da..f229fb7eeb36 100644 --- a/jetty-server/src/main/config/modules/bytebufferpool.mod +++ b/jetty-server/src/main/config/modules/bytebufferpool.mod @@ -1,5 +1,6 @@ [description] Configures the ByteBufferPool used by ServerConnectors. +Use module "bytebufferpool-logarithmic" for a more space efficient pool. [tags] bytebufferpool diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index d69d9c9d39ed..48abdeef43fc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -34,6 +34,7 @@ import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.LogarithmicArrayByteBufferPool; import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.StringUtil; @@ -185,11 +186,27 @@ public AbstractConnector( scheduler = _server.getBean(Scheduler.class); _scheduler = scheduler != null ? scheduler : new ScheduledExecutorScheduler(String.format("Connector-Scheduler-%x", hashCode()), false); addBean(_scheduler); - if (pool == null) - pool = _server.getBean(ByteBufferPool.class); - // TODO improve this - _byteBufferPool = pool != null ? pool : new ArrayByteBufferPool(-1, -1, -1, -1, -1, -1, 0, 0); + synchronized (server) + { + if (pool == null) + { + // Look for (and cache) a common pool on the server + pool = server.getBean(ByteBufferPool.class); + if (pool == null) + { + pool = new LogarithmicArrayByteBufferPool(); + server.addBean(pool, true); + } + addBean(pool, false); + } + else + { + addBean(pool, true); + } + } + + _byteBufferPool = pool; addBean(_byteBufferPool, pool == null); addEventListener(new Container.Listener() From 9d388727b9a277455ac4ceca05839a6a1725d880 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 28 Jun 2022 10:31:42 +1000 Subject: [PATCH 10/24] Combined ByteBufferPool Suspected bug in log pool? Signed-off-by: Greg Wilkins --- .../main/java/org/eclipse/jetty/server/AbstractConnector.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 48abdeef43fc..e538ed78fe29 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -34,7 +34,6 @@ import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.LogarithmicArrayByteBufferPool; import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.StringUtil; @@ -195,7 +194,7 @@ public AbstractConnector( pool = server.getBean(ByteBufferPool.class); if (pool == null) { - pool = new LogarithmicArrayByteBufferPool(); + pool = new ArrayByteBufferPool(); server.addBean(pool, true); } addBean(pool, false); From 58461e0a38d51e7b1cef905e9754cde6a87d2fd8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 28 Jun 2022 11:26:02 +1000 Subject: [PATCH 11/24] Combined ByteBufferPool Increased default factor to reduce buckets. Test LogarithmicArrayByteBufferPool Signed-off-by: Greg Wilkins --- .../jetty/io/AbstractByteBufferPool.java | 2 +- .../io/ArrayRetainableByteBufferPool.java | 2 +- .../io/LogarithmicArrayByteBufferPool.java | 38 ++++++++++++++++++- .../io/ArrayRetainableByteBufferPoolTest.java | 31 +++++++++++++++ .../java/org/eclipse/jetty/util/Pool.java | 2 +- 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index c3efeb337dd3..fbaa9a0d4690 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -55,7 +55,7 @@ abstract class AbstractByteBufferPool implements ByteBufferPool */ protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { - _factor = factor <= 0 ? 1024 : factor; + _factor = factor <= 0 ? 4096 : factor; _maxCapacity = maxCapacity > 0 ? maxCapacity : 64 * _factor; _maxBucketSize = maxBucketSize; _maxHeapMemory = memorySize(maxHeapMemory); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java index e66e42e942e0..90411f155da5 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java @@ -113,7 +113,7 @@ protected ArrayRetainableByteBufferPool(int minCapacity, int factor, int maxCapa if (maxCapacity <= 0) maxCapacity = 64 * 1024; - int f = factor <= 0 ? 1024 : factor; + int f = factor <= 0 ? 4096 : factor; if ((maxCapacity % f) != 0 || f >= maxCapacity) throw new IllegalArgumentException(String.format("The capacity factor(%d) must be a divisor of maxCapacity(%d)", f, maxCapacity)); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java index db586a0ae4b0..9435289cc79f 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LogarithmicArrayByteBufferPool.java @@ -79,7 +79,13 @@ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQ */ public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { - super(minCapacity, 1, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); + super(minCapacity, -1, maxCapacity, maxQueueLength, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); + } + + @Override + protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + { + return new LogarithmicRetainablePool(0, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); } @Override @@ -120,4 +126,34 @@ protected void releaseMemory(boolean direct) bucket.resetUpdateTime(); } } + + /** + * A variant of the {@link ArrayRetainableByteBufferPool} that + * uses buckets of buffers that increase in size by a power of + * 2 (eg 1k, 2k, 4k, 8k, etc.). + */ + public static class LogarithmicRetainablePool extends ArrayRetainableByteBufferPool + { + public LogarithmicRetainablePool() + { + this(0, -1, Integer.MAX_VALUE); + } + + public LogarithmicRetainablePool(int minCapacity, int maxCapacity, int maxBucketSize) + { + this(minCapacity, maxCapacity, maxBucketSize, -1L, -1L); + } + + public LogarithmicRetainablePool(int minCapacity, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory) + { + super(minCapacity, + -1, + maxCapacity, + maxBucketSize, + maxHeapMemory, + maxDirectMemory, + c -> 32 - Integer.numberOfLeadingZeros(c - 1), + i -> 1 << i); + } + } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java index 816352a60d3b..957d9f725246 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java @@ -14,6 +14,7 @@ package org.eclipse.jetty.io; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; @@ -26,7 +27,9 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThan; import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -391,4 +394,32 @@ public void testEndiannessResetOnRelease() assertThat(buffer.release(), is(true)); assertThat(buffer.getBuffer().order(), Matchers.is(ByteOrder.BIG_ENDIAN)); } + + @Test + void testLogarithmic() + { + LogarithmicArrayByteBufferPool pool = new LogarithmicArrayByteBufferPool(); + ByteBuffer buffer5 = pool.acquire(5, false); + pool.release(buffer5); + ByteBuffer buffer6 = pool.acquire(6, false); + assertThat(buffer6, sameInstance(buffer5)); + pool.release(buffer6); + ByteBuffer buffer9 = pool.acquire(9, false); + assertThat(buffer9, not(sameInstance(buffer5))); + pool.release(buffer9); + + RetainableByteBufferPool retainablePool = pool.asRetainableByteBufferPool(); + + RetainableByteBuffer retain5 = retainablePool.acquire(5, false); + retain5.release(); + RetainableByteBuffer retain6 = retainablePool.acquire(6, false); + System.err.println(pool.dump()); + assertThat(retain6, sameInstance(retain5)); + retain6.release(); + RetainableByteBuffer retain9 = retainablePool.acquire(9, false); + assertThat(retain9, not(sameInstance(retain5))); + retain9.release(); + + System.err.println(pool.dump()); + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Pool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Pool.java index 8e12c4f74b25..fa86d040e16f 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Pool.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Pool.java @@ -339,7 +339,7 @@ public Entry reserve() return null; // If we have no space - if (entries.size() >= maxEntries) + if (maxEntries > 0 && entries.size() >= maxEntries) return null; Entry entry = newEntry(); From 7cdd0b7af938f236c0aa4823e2f98bb92a88757d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 28 Jun 2022 13:42:46 +1000 Subject: [PATCH 12/24] Combined ByteBufferPool Further fixes to defaults and tests Signed-off-by: Greg Wilkins --- .../eclipse/jetty/io/AbstractByteBufferPool.java | 10 ++++++---- .../eclipse/jetty/io/ArrayByteBufferPool.java | 16 ++++++++++++++-- .../jetty/io/ArrayRetainableByteBufferPool.java | 14 +++++++------- .../io/ArrayRetainableByteBufferPoolTest.java | 10 +++++----- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index fbaa9a0d4690..544825e0adf0 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -34,6 +34,8 @@ @ManagedObject abstract class AbstractByteBufferPool implements ByteBufferPool { + public static final Integer DEFAULT_FACTOR = 4096; + public static final Integer DEFAULT_MAX_CAPACITY_BY_FACTOR = 16; private final int _factor; private final int _maxCapacity; private final int _maxBucketSize; @@ -55,8 +57,8 @@ abstract class AbstractByteBufferPool implements ByteBufferPool */ protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { - _factor = factor <= 0 ? 4096 : factor; - _maxCapacity = maxCapacity > 0 ? maxCapacity : 64 * _factor; + _factor = factor <= 0 ? DEFAULT_FACTOR : factor; + _maxCapacity = maxCapacity > 0 ? maxCapacity : DEFAULT_MAX_CAPACITY_BY_FACTOR * _factor; _maxBucketSize = maxBucketSize; _maxHeapMemory = memorySize(maxHeapMemory); _maxDirectMemory = memorySize(maxDirectMemory); @@ -65,14 +67,14 @@ protected AbstractByteBufferPool(int factor, int maxCapacity, int maxBucketSize, : newRetainableByteBufferPool(factor, maxCapacity, maxBucketSize, retainedSize(retainedHeapMemory), retainedSize(retainedDirectMemory)); } - private static long retainedSize(long size) + static long retainedSize(long size) { if (size == -2) return 0; return memorySize(size); } - private static long memorySize(long size) + static long memorySize(long size) { if (size < 0) return -1; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index 1b52c7be2607..8ff571d550bf 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -57,6 +57,18 @@ public ArrayByteBufferPool() this(-1, -1, -1); } + /** + * Creates a new ArrayByteBufferPool with a default configuration. + * Both {@code maxHeapMemory} and {@code maxDirectMemory} default to 0 to use default heuristic. + * @param retainable True if {@link #asRetainableByteBufferPool()} return a real implementation. + */ + public ArrayByteBufferPool(boolean retainable) + { + this(-1, -1, -1, -1, -1, -1, + retainable ? -1 : -2, + retainable ? -1 : -2); + } + /** * Creates a new ArrayByteBufferPool with the given configuration. * Both {@code maxHeapMemory} and {@code maxDirectMemory} default to 0 to use default heuristic. @@ -67,7 +79,7 @@ public ArrayByteBufferPool() */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity) { - this(minCapacity, factor, maxCapacity, -1, 0, 0); + this(minCapacity, factor, maxCapacity, -1, -1, -1); } /** @@ -81,7 +93,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity) */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxQueueLength) { - this(minCapacity, factor, maxCapacity, maxQueueLength, 0, 0); + this(minCapacity, factor, maxCapacity, maxQueueLength, -1, -1); } /** diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java index 90411f155da5..9d1069278ec4 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java @@ -110,13 +110,13 @@ protected ArrayRetainableByteBufferPool(int minCapacity, int factor, int maxCapa { if (minCapacity <= 0) minCapacity = 0; + factor = factor <= 0 ? AbstractByteBufferPool.DEFAULT_FACTOR : factor; if (maxCapacity <= 0) - maxCapacity = 64 * 1024; - - int f = factor <= 0 ? 4096 : factor; - if ((maxCapacity % f) != 0 || f >= maxCapacity) - throw new IllegalArgumentException(String.format("The capacity factor(%d) must be a divisor of maxCapacity(%d)", f, maxCapacity)); + maxCapacity = AbstractByteBufferPool.DEFAULT_MAX_CAPACITY_BY_FACTOR * factor; + if ((maxCapacity % factor) != 0 || factor >= maxCapacity) + throw new IllegalArgumentException(String.format("The capacity factor(%d) must be a divisor of maxCapacity(%d)", factor, maxCapacity)); + int f = factor; if (bucketIndexFor == null) bucketIndexFor = c -> (c - 1) / f; if (bucketCapacity == null) @@ -136,8 +136,8 @@ protected ArrayRetainableByteBufferPool(int minCapacity, int factor, int maxCapa _maxCapacity = maxCapacity; _direct = directArray; _indirect = indirectArray; - _maxHeapMemory = (maxHeapMemory != 0L) ? maxHeapMemory : Runtime.getRuntime().maxMemory() / 4; - _maxDirectMemory = (maxDirectMemory != 0L) ? maxDirectMemory : Runtime.getRuntime().maxMemory() / 4; + _maxHeapMemory = AbstractByteBufferPool.retainedSize(maxHeapMemory); + _maxDirectMemory = AbstractByteBufferPool.retainedSize(maxDirectMemory); _bucketIndexFor = bucketIndexFor; } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java index 957d9f725246..4cf0f4298507 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java @@ -241,7 +241,7 @@ public void testClearUnlinksLeakedBuffers() pool.acquire(10, true); assertThat(pool.getDirectByteBufferCount(), is(2L)); - assertThat(pool.getDirectMemory(), is(2048L)); + assertThat(pool.getDirectMemory(), is(2L * AbstractByteBufferPool.DEFAULT_FACTOR)); assertThat(pool.getAvailableDirectByteBufferCount(), is(0L)); assertThat(pool.getAvailableDirectMemory(), is(0L)); @@ -285,16 +285,16 @@ public void testAcquireRelease() { RetainableByteBuffer buf1 = pool.acquire(10, true); assertThat(buf1, is(notNullValue())); - assertThat(buf1.capacity(), is(1024)); + assertThat(buf1.capacity(), is(AbstractByteBufferPool.DEFAULT_FACTOR)); RetainableByteBuffer buf2 = pool.acquire(10, true); assertThat(buf2, is(notNullValue())); - assertThat(buf2.capacity(), is(1024)); + assertThat(buf2.capacity(), is(AbstractByteBufferPool.DEFAULT_FACTOR)); buf1.release(); buf2.release(); RetainableByteBuffer buf3 = pool.acquire(16384 + 1, true); assertThat(buf3, is(notNullValue())); - assertThat(buf3.capacity(), is(16384 + 1024)); + assertThat(buf3.capacity(), is(16384 + AbstractByteBufferPool.DEFAULT_FACTOR)); buf3.release(); RetainableByteBuffer buf4 = pool.acquire(32768, true); @@ -310,7 +310,7 @@ public void testAcquireRelease() assertThat(pool.getDirectByteBufferCount(), is(4L)); assertThat(pool.getHeapByteBufferCount(), is(1L)); - assertThat(pool.getDirectMemory(), is(1024 + 1024 + 16384 + 1024 + 32768L)); + assertThat(pool.getDirectMemory(), is(AbstractByteBufferPool.DEFAULT_FACTOR * 3L + 16384 + 32768L)); assertThat(pool.getHeapMemory(), is(32768L)); pool.clear(); From cb8b422f3f3dd006cca0a0349da53903b909c0d8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 28 Jun 2022 15:20:38 +1000 Subject: [PATCH 13/24] Combined ByteBufferPool @#$&!*#*&#@@ JPMS @!#(*@!%$)*()_!!! Signed-off-by: Greg Wilkins --- .../org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java index 4cf0f4298507..fc1adf863f1c 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java @@ -419,7 +419,5 @@ void testLogarithmic() RetainableByteBuffer retain9 = retainablePool.acquire(9, false); assertThat(retain9, not(sameInstance(retain5))); retain9.release(); - - System.err.println(pool.dump()); } } From 1877f39693544c6f3976b8471f5da8cacec5327a Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 09:53:25 +1000 Subject: [PATCH 14/24] Combined ByteBufferPool Avoid double bean add. Signed-off-by: Greg Wilkins --- .../main/java/org/eclipse/jetty/server/AbstractConnector.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index e538ed78fe29..f3ab9f8d219c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -204,9 +204,7 @@ public AbstractConnector( addBean(pool, true); } } - _byteBufferPool = pool; - addBean(_byteBufferPool, pool == null); addEventListener(new Container.Listener() { From 0dbf44f501c6dd02a2734878b2c2efeb80abbf4d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 10:09:43 +1000 Subject: [PATCH 15/24] Combined ByteBufferPool Updates from review Signed-off-by: Greg Wilkins --- .../config/etc/jetty-bytebufferpool-logarithmic.xml | 2 +- .../src/main/config/etc/jetty-bytebufferpool.xml | 2 +- .../main/config/modules/bytebufferpool-logarithmic.mod | 8 ++++---- .../src/main/config/modules/bytebufferpool.mod | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml b/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml index 4d1fb5039321..39a1e58911c9 100644 --- a/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml +++ b/jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml @@ -4,7 +4,7 @@ - + diff --git a/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml b/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml index d9004974f0c5..ff09a4b35a10 100644 --- a/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml +++ b/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml @@ -5,7 +5,7 @@ - + diff --git a/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod b/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod index 2243cda0916b..a54485b06f27 100644 --- a/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod +++ b/jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod @@ -20,8 +20,8 @@ etc/jetty-bytebufferpool-logarithmic.xml ## Maximum capacity to pool ByteBuffers #jetty.byteBufferPool.maxCapacity=65536 -## Maximum queue length for each bucket (-1 for unbounded) -#jetty.byteBufferPool.maxQueueLength=-1 +## Maximum size for each bucket (-1 for unbounded) +#jetty.byteBufferPool.maxBucketSize=-1 ## Maximum heap memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxHeapMemory=0 @@ -29,8 +29,8 @@ etc/jetty-bytebufferpool-logarithmic.xml ## Maximum direct memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxDirectMemory=0 -## Maximum heap memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +## Maximum heap memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited, -2 for no retained). #jetty.byteBufferPool.retainedHeapMemory=0 -## Maximum direct memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +## Maximum direct memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited, -2 for no retained). #jetty.byteBufferPool.retainedDirectMemory=0 diff --git a/jetty-server/src/main/config/modules/bytebufferpool.mod b/jetty-server/src/main/config/modules/bytebufferpool.mod index f229fb7eeb36..2f651024f573 100644 --- a/jetty-server/src/main/config/modules/bytebufferpool.mod +++ b/jetty-server/src/main/config/modules/bytebufferpool.mod @@ -1,6 +1,6 @@ [description] Configures the ByteBufferPool used by ServerConnectors. -Use module "bytebufferpool-logarithmic" for a more space efficient pool. +Use module "bytebufferpool-logarithmic" for a pool may hold less granulated sized buffers. [tags] bytebufferpool @@ -22,8 +22,8 @@ etc/jetty-bytebufferpool.xml ## a capacity that is multiple of this factor. #jetty.byteBufferPool.factor=1024 -## Maximum queue length for each bucket (-1 for unbounded). -#jetty.byteBufferPool.maxQueueLength=-1 +## Maximum size for each bucket (-1 for unbounded). +#jetty.byteBufferPool.maxBucketSize=-1 ## Maximum heap memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxHeapMemory=0 @@ -31,8 +31,8 @@ etc/jetty-bytebufferpool.xml ## Maximum direct memory held idle by the pool (0 for heuristic, -1 for unlimited). #jetty.byteBufferPool.maxDirectMemory=0 -## Maximum heap memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +## Maximum heap memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited, -2 for no retained). #jetty.byteBufferPool.retainedHeapMemory=0 -## Maximum direct memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited). +## Maximum direct memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited, -2 for no retained). #jetty.byteBufferPool.retainedDirectMemory=0 \ No newline at end of file From c5c0ca90faaad9db1a1fb53658982abfbc5bf053 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 10:13:01 +1000 Subject: [PATCH 16/24] Combined ByteBufferPool Fixed JPMS issue Signed-off-by: Greg Wilkins --- .../eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java index fc1adf863f1c..637429c6a588 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPoolTest.java @@ -396,7 +396,7 @@ public void testEndiannessResetOnRelease() } @Test - void testLogarithmic() + public void testLogarithmic() { LogarithmicArrayByteBufferPool pool = new LogarithmicArrayByteBufferPool(); ByteBuffer buffer5 = pool.acquire(5, false); @@ -413,7 +413,6 @@ void testLogarithmic() RetainableByteBuffer retain5 = retainablePool.acquire(5, false); retain5.release(); RetainableByteBuffer retain6 = retainablePool.acquire(6, false); - System.err.println(pool.dump()); assertThat(retain6, sameInstance(retain5)); retain6.release(); RetainableByteBuffer retain9 = retainablePool.acquire(9, false); From 5c4abfad6e7a6182d2b5536372adf9d93a6a2d64 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 11:01:50 +1000 Subject: [PATCH 17/24] Combined ByteBufferPool Fixed async IO write test Signed-off-by: Greg Wilkins --- .../jetty/server/AbstractConnector.java | 3 +- .../jetty/server/AsyncCompletionTest.java | 49 ++++++++----------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index f3ab9f8d219c..932e852a4e21 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -34,6 +34,7 @@ import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.LogarithmicArrayByteBufferPool; import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.StringUtil; @@ -194,7 +195,7 @@ public AbstractConnector( pool = server.getBean(ByteBufferPool.class); if (pool == null) { - pool = new ArrayByteBufferPool(); + pool = new LogarithmicArrayByteBufferPool(); server.addBean(pool, true); } addBean(pool, false); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java index d5703e09baee..997f0b383462 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java @@ -210,46 +210,39 @@ public void testAsyncIOWrite(AsyncIOWriteHandler handler) throws Exception os.write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1)); os.flush(); - // wait for OWP to execute (proves we do not block in write APIs) - boolean completeCalled = handler.waitForOWPExit(); - while (true) { - // wait for threads to return to base level (proves we are really async) + PendingCallback delay = __queue.poll(POLL, TimeUnit.MILLISECONDS); + Boolean owpExit = handler.pollForOWPExit(); + if (owpExit == null) + { + // handle any callback written so far + while (delay != null) + { + delay.proceed(); + delay = __queue.poll(POLL, TimeUnit.MILLISECONDS); + } + continue; + } + + // OWP has exited, but we have a delay, so let's wait for thread to return to the pool to ensure we are async. long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(WAIT); - while (_threadPool.getBusyThreads() != base) + while (delay != null && _threadPool.getBusyThreads() > base) { if (System.nanoTime() > end) throw new TimeoutException(); Thread.sleep(POLL); } - if (completeCalled) - break; - - // We are now asynchronously waiting! - assertThat(__transportComplete.get(), is(false)); - - // If we are not complete, we must be waiting for one or more writes to complete - while (true) + // handle any callback written so far + while (delay != null) { - PendingCallback delay = __queue.poll(POLL, TimeUnit.MILLISECONDS); - if (delay != null) - { - delay.proceed(); - continue; - } - // No delay callback found, have we finished OWP again? - Boolean c = handler.pollForOWPExit(); - - if (c == null) - // No we haven't, so look for another delay callback - continue; + delay.proceed(); + delay = __queue.poll(POLL, TimeUnit.MILLISECONDS); + } - // We have a OWP result, so let's handle it. - completeCalled = c; + if (owpExit) break; - } } // Wait for full completion From b61d133ee711d21df5f8542ec954c3a0c51b8811 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 11:29:55 +1000 Subject: [PATCH 18/24] Combined ByteBufferPool Fixed BufferedResponseHandlerTest Signed-off-by: Greg Wilkins --- .../jetty/server/handler/BufferedResponseHandlerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BufferedResponseHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BufferedResponseHandlerTest.java index b4072cf28afe..906d09ad528b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BufferedResponseHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BufferedResponseHandlerTest.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.io.NullByteBufferPool; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.LocalConnector; @@ -49,6 +50,7 @@ public class BufferedResponseHandlerTest public static void setUp() throws Exception { _server = new Server(); + _server.addBean(new NullByteBufferPool()); // Avoid giving larger buffers than requested _config = new HttpConfiguration(); _config.setOutputBufferSize(1024); _config.setOutputAggregationSize(256); From 9e1cf323129832e78e30d29e205e917d808cfe7e Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 13:11:05 +1000 Subject: [PATCH 19/24] Combined ByteBufferPool Fixed more tests Signed-off-by: Greg Wilkins --- .../jetty/client/HttpClientTLSTest.java | 69 ++++++++++++++++--- .../eclipse/jetty/io/ArrayByteBufferPool.java | 4 +- .../jetty/io/RetainableByteBufferPool.java | 7 ++ 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java index e4d5358cf78d..c715ac5caa0f 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java @@ -708,6 +708,54 @@ protected int networkFill(ByteBuffer input) throws IOException assertEquals(0, clientBytes.get()); } + protected class TestRetained extends ArrayRetainableByteBufferPool + { + private final ByteBufferPool _pool; + + public TestRetained(ByteBufferPool pool, int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + { + super(0, factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); + _pool = pool; + } + + @Override + protected ByteBuffer allocate(int capacity) + { + System.err.println("allocate " + capacity); + new Throwable().printStackTrace(); + return _pool.acquire(capacity, false); + } + + @Override + protected ByteBuffer allocateDirect(int capacity) + { + System.err.println("allocateDirect " + capacity); + new Throwable().printStackTrace(); + return _pool.acquire(capacity, true); + } + + @Override + protected void removed(RetainableByteBuffer retainedBuffer) + { + _pool.release(retainedBuffer.getBuffer()); + } + + @Override + public Pool poolFor(int capacity, boolean direct) + { + return super.poolFor(capacity, direct); + } + } + + private class TestByteBufferPool extends ArrayByteBufferPool + { + @Override + protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + { + return new TestRetained(this, factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); + } + } + @Test public void testEncryptedInputBufferRepooling() throws Exception { @@ -715,15 +763,10 @@ public void testEncryptedInputBufferRepooling() throws Exception QueuedThreadPool serverThreads = new QueuedThreadPool(); serverThreads.setName("server"); server = new Server(serverThreads); - var retainableByteBufferPool = new ArrayRetainableByteBufferPool() - { - @Override - public Pool poolFor(int capacity, boolean direct) - { - return super.poolFor(capacity, direct); - } - }; - server.addBean(retainableByteBufferPool); + + ArrayByteBufferPool byteBufferPool = new TestByteBufferPool(); + RetainableByteBufferPool retainableByteBufferPool = byteBufferPool.asRetainableByteBufferPool(); + server.addBean(byteBufferPool); HttpConfiguration httpConfig = new HttpConfiguration(); httpConfig.addCustomizer(new SecureRequestCustomizer()); HttpConnectionFactory http = new HttpConnectionFactory(httpConfig); @@ -765,9 +808,12 @@ protected int networkFill(ByteBuffer input) throws IOException assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send()); - Pool bucket = retainableByteBufferPool.poolFor(16 * 1024 + 1, ssl.isDirectBuffersForEncryption()); + Pool bucket = ((TestRetained)retainableByteBufferPool).poolFor(16 * 1024 + 1, connector.getConnectionFactory(HttpConnectionFactory.class).isUseInputDirectByteBuffers()); assertEquals(1, bucket.size()); assertEquals(1, bucket.getIdleCount()); + + long count = ssl.isDirectBuffersForDecryption() ? byteBufferPool.getDirectByteBufferCount() : byteBufferPool.getHeapByteBufferCount(); + assertEquals(1, count); } @Test @@ -834,6 +880,7 @@ protected boolean networkFlush(ByteBuffer output) throws IOException assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send()); + byteBufferPool.asRetainableByteBufferPool().clear(); await().atMost(5, TimeUnit.SECONDS).until(() -> leakedBuffers, is(empty())); } @@ -916,6 +963,7 @@ protected void service(String target, Request jettyRequest, HttpServletRequest r assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send()); + byteBufferPool.asRetainableByteBufferPool().clear(); await().atMost(5, TimeUnit.SECONDS).until(() -> leakedBuffers, is(empty())); } @@ -998,6 +1046,7 @@ protected void service(String target, Request jettyRequest, HttpServletRequest r assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send()); + byteBufferPool.asRetainableByteBufferPool().clear(); await().atMost(5, TimeUnit.SECONDS).until(() -> leakedBuffers, is(empty())); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index 8ff571d550bf..f10297a07a89 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -244,7 +244,7 @@ protected int capacityFor(int bucket) return bucket * getCapacityFactor(); } - private Bucket bucketFor(int capacity, boolean direct) + protected Bucket bucketFor(int capacity, boolean direct) { if (capacity < _minCapacity) return null; @@ -327,7 +327,7 @@ public String toString() protected class Retained extends ArrayRetainableByteBufferPool { - Retained(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) + public Retained(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory) { super(0, factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java index 0831bb636c84..c6393c18c370 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBufferPool.java @@ -30,6 +30,8 @@ public interface RetainableByteBufferPool */ RetainableByteBuffer acquire(int size, boolean direct); + void clear(); + static RetainableByteBufferPool from(ByteBufferPool byteBufferPool) { return new RetainableByteBufferPool() @@ -48,6 +50,11 @@ private void release(RetainableByteBuffer retainedBuffer) byteBufferPool.release(retainedBuffer.getBuffer()); } + @Override + public void clear() + { + } + @Override public String toString() { From 78edb9cbb94a9cebb1bf0fd58f734796cc0ed1a6 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 14:10:48 +1000 Subject: [PATCH 20/24] Combined ByteBufferPool Fixed FastCGI that was expecting a larger buffer than requested Signed-off-by: Greg Wilkins --- .../java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java index 132a2823171b..cd75698f92c1 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java @@ -120,7 +120,7 @@ public Result generateResponseContent(int request, ByteBuffer content, boolean l private ByteBuffer generateEndRequest(int request, boolean aborted) { request &= 0xFF_FF; - ByteBuffer endRequestBuffer = acquire(8); + ByteBuffer endRequestBuffer = acquire(16); BufferUtil.clearToFill(endRequestBuffer); endRequestBuffer.putInt(0x01_03_00_00 + request); endRequestBuffer.putInt(0x00_08_00_00); From 80ac54712b2d2f2b3d8d6036fd795c39154903a7 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Jun 2022 15:43:02 +1000 Subject: [PATCH 21/24] Combined ByteBufferPool minor cleanups Signed-off-by: Greg Wilkins --- .../main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java | 6 +++--- jetty-server/src/main/config/etc/jetty-bytebufferpool.xml | 2 +- jetty-server/src/main/config/modules/bytebufferpool.mod | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index f10297a07a89..f63dd5b58a68 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -31,9 +31,9 @@ /** *

A ByteBuffer pool where ByteBuffers are held in queues that are held in array elements.

- *

Given a capacity {@code factor} of 1024, the first array element holds a queue of ByteBuffers - * each of capacity 1024, the second array element holds a queue of ByteBuffers each of capacity - * 2048, and so on.

+ *

Given a capacity {@code factor} of 4096, the first array element holds a bucket of ByteBuffers + * each of capacity 4096, the second array element holds a bucket of ByteBuffers each of capacity + * 8192, and so on.

*

The {@code maxHeapMemory} and {@code maxDirectMemory} default heuristic is to use {@link Runtime#maxMemory()} * divided by 4.

*/ diff --git a/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml b/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml index ff09a4b35a10..f1d787a62018 100644 --- a/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml +++ b/jetty-server/src/main/config/etc/jetty-bytebufferpool.xml @@ -3,7 +3,7 @@ - + diff --git a/jetty-server/src/main/config/modules/bytebufferpool.mod b/jetty-server/src/main/config/modules/bytebufferpool.mod index 2f651024f573..97e8b5217cfd 100644 --- a/jetty-server/src/main/config/modules/bytebufferpool.mod +++ b/jetty-server/src/main/config/modules/bytebufferpool.mod @@ -20,7 +20,7 @@ etc/jetty-bytebufferpool.xml ## Bucket capacity factor. ## ByteBuffers are allocated out of buckets that have ## a capacity that is multiple of this factor. -#jetty.byteBufferPool.factor=1024 +#jetty.byteBufferPool.factor=4096 ## Maximum size for each bucket (-1 for unbounded). #jetty.byteBufferPool.maxBucketSize=-1 @@ -35,4 +35,4 @@ etc/jetty-bytebufferpool.xml #jetty.byteBufferPool.retainedHeapMemory=0 ## Maximum direct memory retained whilst in use by the pool (0 for heuristic, -1 for unlimited, -2 for no retained). -#jetty.byteBufferPool.retainedDirectMemory=0 \ No newline at end of file +#jetty.byteBufferPool.retainedDirectMemory=0 From c2d261efb0637b329972eecabf50654f920db8e3 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 1 Jul 2022 08:28:11 +1000 Subject: [PATCH 22/24] Combined ByteBufferPool Updates from review Signed-off-by: Greg Wilkins --- .../java/org/eclipse/jetty/io/AbstractByteBufferPool.java | 4 ++-- .../main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java | 4 ++-- .../main/java/org/eclipse/jetty/io/NullByteBufferPool.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java index 544825e0adf0..e4aca8c0f079 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -34,8 +34,8 @@ @ManagedObject abstract class AbstractByteBufferPool implements ByteBufferPool { - public static final Integer DEFAULT_FACTOR = 4096; - public static final Integer DEFAULT_MAX_CAPACITY_BY_FACTOR = 16; + public static final int DEFAULT_FACTOR = 4096; + public static final int DEFAULT_MAX_CAPACITY_BY_FACTOR = 16; private final int _factor; private final int _maxCapacity; private final int _maxBucketSize; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index f63dd5b58a68..c0fdd5a27801 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -79,7 +79,7 @@ public ArrayByteBufferPool(boolean retainable) */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity) { - this(minCapacity, factor, maxCapacity, -1, -1, -1); + this(minCapacity, factor, maxCapacity, -1, 0, 0); } /** @@ -93,7 +93,7 @@ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity) */ public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxQueueLength) { - this(minCapacity, factor, maxCapacity, maxQueueLength, -1, -1); + this(minCapacity, factor, maxCapacity, maxQueueLength, 0, 0); } /** diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java index 88ab24651f68..cb06a1014769 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java @@ -19,7 +19,7 @@ public class NullByteBufferPool implements ByteBufferPool { - private RetainableByteBufferPool _retainableByteBufferPool = RetainableByteBufferPool.from(this); + private final RetainableByteBufferPool _retainableByteBufferPool = RetainableByteBufferPool.from(this); @Override public ByteBuffer acquire(int size, boolean direct) From 02bc66d361b8c2514e0ec51135f706ed4eb9ca11 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 1 Jul 2022 08:36:19 +1000 Subject: [PATCH 23/24] Combined ByteBufferPool Updates from review Signed-off-by: Greg Wilkins --- .../jetty/io/MappedByteBufferPool.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java index 4ac8f482e568..fb5c55738df4 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java @@ -69,67 +69,67 @@ public MappedByteBufferPool(int factor) * Creates a new MappedByteBufferPool with the given configuration. * * @param factor the capacity factor - * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxBucketSize the maximum ByteBuffer bucket size */ - public MappedByteBufferPool(int factor, int maxQueueLength) + public MappedByteBufferPool(int factor, int maxBucketSize) { - this(factor, maxQueueLength, null); + this(factor, maxBucketSize, null); } /** * Creates a new MappedByteBufferPool with the given configuration. * * @param factor the capacity factor - * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxBucketSize the maximum ByteBuffer bucket size * @param newBucket the function that creates a Bucket */ - private MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket) + private MappedByteBufferPool(int factor, int maxBucketSize, Function newBucket) { - this(factor, maxQueueLength, newBucket, -1, -1, -1, -1); + this(factor, maxBucketSize, newBucket, 0, 0, 0, 0); } /** * Creates a new MappedByteBufferPool with the given configuration. * * @param factor the capacity factor - * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxBucketSize the maximum ByteBuffer bucket size * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic. * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic. */ - public MappedByteBufferPool(int factor, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) + public MappedByteBufferPool(int factor, int maxBucketSize, long maxHeapMemory, long maxDirectMemory) { - this(factor, maxQueueLength, null, maxHeapMemory, maxDirectMemory, maxHeapMemory, maxDirectMemory); + this(factor, maxBucketSize, null, maxHeapMemory, maxDirectMemory, maxHeapMemory, maxDirectMemory); } /** * Creates a new MappedByteBufferPool with the given configuration. * * @param factor the capacity factor - * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxBucketSize the maximum ByteBuffer bucket size * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic. * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic. * @param retainedHeapMemory the max heap memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic * @param retainedDirectMemory the max direct memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic */ - public MappedByteBufferPool(int factor, int maxQueueLength, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) + public MappedByteBufferPool(int factor, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { - this(factor, maxQueueLength, null, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); + this(factor, maxBucketSize, null, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); } /** * Creates a new MappedByteBufferPool with the given configuration. * * @param factor the capacity factor - * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxBucketSize the maximum ByteBuffer bucket size * @param newBucket the function that creates a Bucket * @param maxHeapMemory the max heap memory in bytes, -1 for unlimited memory or 0 to use default heuristic. * @param maxDirectMemory the max direct memory in bytes, -1 for unlimited memory or 0 to use default heuristic. * @param retainedHeapMemory the max heap memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic * @param retainedDirectMemory the max direct memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic */ - private MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) + private MappedByteBufferPool(int factor, int maxBucketSize, Function newBucket, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory) { - super(factor, 0, maxQueueLength, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); + super(factor, 0, maxBucketSize, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory); _newBucket = newBucket; } From 0cfc50cd4d24e5418975fd3b5fbb17baccf00072 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Sat, 2 Jul 2022 15:11:15 +1000 Subject: [PATCH 24/24] Combined ByteBufferPool Updates from review Signed-off-by: Greg Wilkins --- .../org/eclipse/jetty/client/HttpClientTLSTest.java | 12 ++++-------- .../org/eclipse/jetty/io/ArrayByteBufferPool.java | 12 ------------ 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java index c715ac5caa0f..14fc9994c3f6 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java @@ -22,9 +22,9 @@ import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; @@ -721,16 +721,12 @@ public TestRetained(ByteBufferPool pool, int factor, int maxCapacity, int maxBuc @Override protected ByteBuffer allocate(int capacity) { - System.err.println("allocate " + capacity); - new Throwable().printStackTrace(); return _pool.acquire(capacity, false); } @Override protected ByteBuffer allocateDirect(int capacity) { - System.err.println("allocateDirect " + capacity); - new Throwable().printStackTrace(); return _pool.acquire(capacity, true); } @@ -823,7 +819,7 @@ public void testEncryptedOutputBufferRepooling() throws Exception QueuedThreadPool serverThreads = new QueuedThreadPool(); serverThreads.setName("server"); server = new Server(serverThreads); - List leakedBuffers = new ArrayList<>(); + List leakedBuffers = new CopyOnWriteArrayList<>(); ArrayByteBufferPool byteBufferPool = new ArrayByteBufferPool() { @Override @@ -892,7 +888,7 @@ public void testEncryptedOutputBufferRepoolingAfterNetworkFlushReturnsFalse(bool QueuedThreadPool serverThreads = new QueuedThreadPool(); serverThreads.setName("server"); server = new Server(serverThreads); - List leakedBuffers = new ArrayList<>(); + List leakedBuffers = new CopyOnWriteArrayList<>(); ArrayByteBufferPool byteBufferPool = new ArrayByteBufferPool() { @Override @@ -975,7 +971,7 @@ public void testEncryptedOutputBufferRepoolingAfterNetworkFlushThrows(boolean cl QueuedThreadPool serverThreads = new QueuedThreadPool(); serverThreads.setName("server"); server = new Server(serverThreads); - List leakedBuffers = new ArrayList<>(); + List leakedBuffers = new CopyOnWriteArrayList<>(); ArrayByteBufferPool byteBufferPool = new ArrayByteBufferPool() { @Override diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index c0fdd5a27801..61e407d65845 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -57,18 +57,6 @@ public ArrayByteBufferPool() this(-1, -1, -1); } - /** - * Creates a new ArrayByteBufferPool with a default configuration. - * Both {@code maxHeapMemory} and {@code maxDirectMemory} default to 0 to use default heuristic. - * @param retainable True if {@link #asRetainableByteBufferPool()} return a real implementation. - */ - public ArrayByteBufferPool(boolean retainable) - { - this(-1, -1, -1, -1, -1, -1, - retainable ? -1 : -2, - retainable ? -1 : -2); - } - /** * Creates a new ArrayByteBufferPool with the given configuration. * Both {@code maxHeapMemory} and {@code maxDirectMemory} default to 0 to use default heuristic.