From 8c6ad12088454bb584522a9dbd03a0823d3a0d44 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 29 Aug 2012 20:16:31 +1000 Subject: [PATCH] jetty-9 fixed ArrayByteBufferPool and added test --- .../eclipse/jetty/io/ArrayByteBufferPool.java | 26 +++- .../jetty/io/ArrayByteBufferPoolTest.java | 147 ++++++++++++++++++ 2 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java 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 32b24dbb6b9..468f2aa62e6 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 @@ -21,6 +21,7 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentMap; import org.eclipse.jetty.util.BufferUtil; @@ -96,20 +97,35 @@ public class ArrayByteBufferPool implements ByteBufferPool { if (size<=_min) return null; - int b=size/_inc; + int b=(size-1)/_inc; if (b>=_direct.length) return null; - return direct?_direct[b]:_indirect[b]; + Bucket bucket = direct?_direct[b]:_indirect[b]; + + return bucket; } - private static class Bucket + public static class Bucket { - final int _size; - final Queue _queue= new ConcurrentLinkedQueue<>(); + public final int _size; + public final Queue _queue= new ConcurrentLinkedQueue<>(); Bucket(int size) { _size=size; } + + @Override + public String toString() + { + return String.format("Bucket@%x{%d,%d}",hashCode(),_size,_queue.size()); + } + } + + + // Package local for testing + Bucket[] bucketsFor(boolean direct) + { + return direct ? _direct : _indirect; } } 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 new file mode 100644 index 00000000000..250922a4845 --- /dev/null +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java @@ -0,0 +1,147 @@ +// +// ======================================================================== +// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.io; + +import java.nio.ByteBuffer; + +import org.hamcrest.Matchers; +import org.junit.Test; + +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class ArrayByteBufferPoolTest +{ + @Test + public void testMinimumRelease() throws Exception + { + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); + ArrayByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + + for (int size=1;size<=9;size++) + { + ByteBuffer buffer = bufferPool.acquire(size, true); + + assertTrue(buffer.isDirect()); + assertEquals(size,buffer.capacity()); + for (ArrayByteBufferPool.Bucket bucket : buckets) + assertTrue(bucket._queue.isEmpty()); + + bufferPool.release(buffer); + + for (ArrayByteBufferPool.Bucket bucket : buckets) + assertTrue(bucket._queue.isEmpty()); + } + } + + @Test + public void testMaxRelease() throws Exception + { + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); + ArrayByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + + for (int size=999;size<=1001;size++) + { + bufferPool.clear(); + ByteBuffer buffer = bufferPool.acquire(size, true); + + assertTrue(buffer.isDirect()); + assertThat(buffer.capacity(),greaterThanOrEqualTo(size)); + for (ArrayByteBufferPool.Bucket bucket : buckets) + assertTrue(bucket._queue.isEmpty()); + + bufferPool.release(buffer); + + int pooled=0; + for (ArrayByteBufferPool.Bucket bucket : buckets) + { + pooled+=bucket._queue.size(); + } + assertEquals(size<=1000,1==pooled); + } + } + + @Test + public void testAcquireRelease() throws Exception + { + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); + ArrayByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + + for (int size=390;size<=510;size++) + { + bufferPool.clear(); + ByteBuffer buffer = bufferPool.acquire(size, true); + + assertTrue(buffer.isDirect()); + assertThat(buffer.capacity(), greaterThanOrEqualTo(size)); + for (ArrayByteBufferPool.Bucket bucket : buckets) + assertTrue(bucket._queue.isEmpty()); + + bufferPool.release(buffer); + + int pooled=0; + for (ArrayByteBufferPool.Bucket bucket : buckets) + { + if (!bucket._queue.isEmpty()) + { + pooled+=bucket._queue.size(); + assertThat(bucket._size,greaterThanOrEqualTo(size)); + assertThat(bucket._size,Matchers.lessThan(size+100)); + } + } + assertEquals(1,pooled); + } + } + + @Test + public void testAcquireReleaseAcquire() throws Exception + { + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); + ArrayByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + + for (int size=390;size<=510;size++) + { + bufferPool.clear(); + ByteBuffer buffer1 = bufferPool.acquire(size, true); + bufferPool.release(buffer1); + ByteBuffer buffer2 = bufferPool.acquire(size, true); + bufferPool.release(buffer2); + ByteBuffer buffer3 = bufferPool.acquire(size, false); + bufferPool.release(buffer3); + + int pooled=0; + for (ArrayByteBufferPool.Bucket bucket : buckets) + { + if (!bucket._queue.isEmpty()) + { + pooled+=bucket._queue.size(); + assertThat(bucket._size,greaterThanOrEqualTo(size)); + assertThat(bucket._size,Matchers.lessThan(size+100)); + } + } + assertEquals(1,pooled); + + assertTrue(buffer1==buffer2); + assertTrue(buffer1!=buffer3); + } + } + +}