- Replace ByteBufferPool + size + directness with ByteBufferPool.Sized in HttpContent-related code

- Cleanup and javadoc HttpContent
 - Align and cleanup offset/length default values

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2024-07-24 14:54:20 +02:00
parent bcd73c6a7b
commit 347dee0ba5
19 changed files with 226 additions and 261 deletions

View File

@ -222,7 +222,7 @@ public class MultiPartByteRanges
{
private final Resource resource;
private final ByteRange byteRange;
private final ByteBufferPool bufferPool;
private final ByteBufferPool.Sized bufferPool;
public Part(String contentType, Resource resource, ByteRange byteRange, long contentLength)
{
@ -233,7 +233,7 @@ public class MultiPartByteRanges
public Part(String contentType, Resource resource, ByteRange byteRange, long contentLength, ByteBufferPool bufferPool)
{
this(HttpFields.build().put(HttpHeader.CONTENT_TYPE, contentType)
.put(HttpHeader.CONTENT_RANGE, byteRange.toHeaderValue(contentLength)), resource, byteRange, bufferPool);
.put(HttpHeader.CONTENT_RANGE, byteRange.toHeaderValue(contentLength)), resource, byteRange, new ByteBufferPool.Sized(bufferPool));
}
public Part(HttpFields headers, Resource resource, ByteRange byteRange)
@ -241,18 +241,18 @@ public class MultiPartByteRanges
this(headers, resource, byteRange, null);
}
public Part(HttpFields headers, Resource resource, ByteRange byteRange, ByteBufferPool bufferPool)
public Part(HttpFields headers, Resource resource, ByteRange byteRange, ByteBufferPool.Sized bufferPool)
{
super(null, null, headers);
this.resource = resource;
this.byteRange = byteRange;
this.bufferPool = bufferPool == null ? ByteBufferPool.NON_POOLING : bufferPool;
this.bufferPool = bufferPool == null ? ByteBufferPool.SIZED_NON_POOLING : bufferPool;
}
@Override
public Content.Source newContentSource()
{
return IOResources.asContentSource(resource, bufferPool, 0, false, byteRange.first(), byteRange.getLength());
return IOResources.asContentSource(resource, bufferPool, byteRange.first(), byteRange.getLength());
}
}

View File

@ -69,16 +69,15 @@ public class CachingHttpContentFactory implements HttpContent.Factory
private final HttpContent.Factory _authority;
private final ConcurrentHashMap<String, CachingHttpContent> _cache = new ConcurrentHashMap<>();
private final AtomicLong _cachedSize = new AtomicLong();
private final ByteBufferPool _bufferPool;
private final ByteBufferPool.Sized _bufferPool;
private int _maxCachedFileSize = DEFAULT_MAX_CACHED_FILE_SIZE;
private int _maxCachedFiles = DEFAULT_MAX_CACHED_FILES;
private long _maxCacheSize = DEFAULT_MAX_CACHE_SIZE;
private boolean _useDirectByteBuffers = true;
public CachingHttpContentFactory(HttpContent.Factory authority, ByteBufferPool bufferPool)
public CachingHttpContentFactory(HttpContent.Factory authority, ByteBufferPool.Sized bufferPool)
{
_authority = authority;
_bufferPool = bufferPool != null ? bufferPool : ByteBufferPool.NON_POOLING;
_bufferPool = bufferPool != null ? bufferPool : ByteBufferPool.SIZED_NON_POOLING;
}
protected ConcurrentMap<String, CachingHttpContent> getCache()
@ -137,16 +136,6 @@ public class CachingHttpContentFactory implements HttpContent.Factory
shrinkCache();
}
public boolean isUseDirectByteBuffers()
{
return _useDirectByteBuffers;
}
public void setUseDirectByteBuffers(boolean useDirectByteBuffers)
{
_useDirectByteBuffers = useDirectByteBuffers;
}
private void shrinkCache()
{
// While we need to shrink
@ -334,7 +323,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
throw new IllegalArgumentException("Resource is too large: length " + contentLengthValue + " > " + _maxCachedFileSize);
// Read the content into memory
_buffer = IOResources.toRetainableByteBuffer(httpContent.getResource(), _bufferPool, _useDirectByteBuffers);
_buffer = IOResources.toRetainableByteBuffer(httpContent.getResource(), _bufferPool);
_characterEncoding = httpContent.getCharacterEncoding();
_compressedFormats = httpContent.getPreCompressedContentFormats();

View File

@ -121,7 +121,7 @@ public class ResourceHttpContent implements HttpContent
@Override
public void writeTo(Content.Sink sink, long offset, long length, Callback callback)
{
IOResources.copy(_resource, sink, _sizedBufferPool, _sizedBufferPool.getSize(), _sizedBufferPool.isDirect(), offset, length, callback);
IOResources.copy(_resource, sink, _sizedBufferPool, offset, length, callback);
}
@Override

View File

@ -59,7 +59,7 @@ public class ValidatingCachingHttpContentFactory extends CachingHttpContentFacto
*/
public ValidatingCachingHttpContentFactory(@Name("authority") HttpContent.Factory authority,
@Name("validationPeriod") long validationPeriod,
@Name("bufferPool") ByteBufferPool bufferPool)
@Name("bufferPool") ByteBufferPool.Sized bufferPool)
{
this(authority, validationPeriod, bufferPool, null, -1, -1);
}
@ -77,7 +77,7 @@ public class ValidatingCachingHttpContentFactory extends CachingHttpContentFacto
*/
public ValidatingCachingHttpContentFactory(@Name("authority") HttpContent.Factory authority,
@Name("validationPeriod") long validationPeriod,
@Name("byteBufferPool") ByteBufferPool bufferPool,
@Name("byteBufferPool") ByteBufferPool.Sized bufferPool,
@Name("scheduler") Scheduler scheduler,
@Name("sweepPeriod") long sweepPeriod,
@Name("idleTimeout") long idleTimeout)

View File

@ -150,12 +150,30 @@ public interface ByteBufferPool
}
/**
* @return A {@link RetainableByteBuffer} suitable for the specified preconfigured size and type.
* @return A {@link RetainableByteBuffer.Mutable} suitable for the specified preconfigured size and type.
*/
public RetainableByteBuffer acquire()
public RetainableByteBuffer.Mutable acquire()
{
return getWrapped().acquire(_size, _direct);
}
/**
* @return A {@link RetainableByteBuffer.Mutable} suitable for the specified preconfigured type.
* @param size The specified size in bytes of the buffer
*/
public RetainableByteBuffer.Mutable acquire(int size)
{
return getWrapped().acquire(size, _direct);
}
/**
* @return A {@link RetainableByteBuffer.Mutable} suitable for the specified preconfigured type.
* @param direct true for a direct byte buffer, false otherwise
*/
public RetainableByteBuffer.Mutable acquire(boolean direct)
{
return getWrapped().acquire(_size, direct);
}
}
/**

View File

@ -209,7 +209,7 @@ public class Content
* @param byteBufferPool The {@link org.eclipse.jetty.io.ByteBufferPool.Sized} to use for any internal buffers.
* @param path The {@link Path}s to use as the source.
* @param offset The offset in bytes from which to start the source
* @param length The length in bytes of the source.
* @param length The length in bytes of the source, -1 for the full length.
* @return A {@code Content.Source}
*/
static Content.Source from(ByteBufferPool.Sized byteBufferPool, Path path, long offset, long length)
@ -247,7 +247,7 @@ public class Content
}
/**
* Create a {@code Content.Source} from a {@link Path}.
* Create a {@code Content.Source} from an {@link InputStream}.
* @param byteBufferPool The {@link org.eclipse.jetty.io.ByteBufferPool.Sized} to use for any internal buffers.
* @param inputStream The {@link InputStream}s to use as the source.
* @return A {@code Content.Source}
@ -258,7 +258,7 @@ public class Content
}
/**
* Create a {@code Content.Source} from a {@link Path}.
* Create a {@code Content.Source} from an {@link InputStream}.
* @param byteBufferPool The {@link org.eclipse.jetty.io.ByteBufferPool.Sized} to use for any internal buffers.
* @param inputStream The {@link InputStream}s to use as the source.
* @param offset The offset in bytes from which to start the source

View File

@ -20,8 +20,6 @@ import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import org.eclipse.jetty.io.content.ByteBufferContentSource;
import org.eclipse.jetty.io.content.InputStreamContentSource;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
@ -31,7 +29,6 @@ import org.eclipse.jetty.util.resource.Resource;
/**
* Common IO operations for {@link Resource} content.
* // TODO use ByteBufferPool.Sized instead of ByteBufferPool in all signatures.
*/
public class IOResources
{
@ -43,12 +40,11 @@ public class IOResources
* {@link Resource#newInputStream()} is used as a fallback.</p>
*
* @param resource the resource to be read.
* @param bufferPool the {@link ByteBufferPool} to get buffers from. null means allocate new buffers as needed.
* @param direct the directness of the buffers.
* @param bufferPool the {@link ByteBufferPool.Sized} to get buffers from. null means allocate new buffers as needed.
* @return a {@link RetainableByteBuffer} containing the resource's contents.
* @throws IllegalArgumentException if the resource is a directory or does not exist or there is no way to access its contents.
*/
public static RetainableByteBuffer toRetainableByteBuffer(Resource resource, ByteBufferPool bufferPool, boolean direct) throws IllegalArgumentException
public static RetainableByteBuffer toRetainableByteBuffer(Resource resource, ByteBufferPool.Sized bufferPool) throws IllegalArgumentException
{
if (resource.isDirectory() || !resource.exists())
throw new IllegalArgumentException("Resource must exist and cannot be a directory: " + resource);
@ -59,14 +55,14 @@ public class IOResources
long longLength = resource.length();
bufferPool = bufferPool == null ? ByteBufferPool.NON_POOLING : bufferPool;
bufferPool = bufferPool == null ? ByteBufferPool.SIZED_NON_POOLING : bufferPool;
// Optimize for PathResource.
Path path = resource.getPath();
if (path != null && longLength < Integer.MAX_VALUE)
{
// TODO convert to a Dynamic once HttpContent uses writeTo semantics
RetainableByteBuffer retainableByteBuffer = bufferPool.acquire((int)longLength, direct);
RetainableByteBuffer retainableByteBuffer = bufferPool.acquire((int)longLength);
try (SeekableByteChannel seekableByteChannel = Files.newByteChannel(path))
{
long totalRead = 0L;
@ -96,11 +92,11 @@ public class IOResources
if (inputStream == null)
throw new IllegalArgumentException("Resource does not support InputStream: " + resource);
RetainableByteBuffer.DynamicCapacity retainableByteBuffer = new RetainableByteBuffer.DynamicCapacity(bufferPool, direct, longLength);
RetainableByteBuffer.DynamicCapacity retainableByteBuffer = new RetainableByteBuffer.DynamicCapacity(bufferPool, bufferPool.isDirect(), longLength);
while (true)
{
if (buffer == null)
buffer = bufferPool.acquire(8192, false);
buffer = bufferPool.acquire(false);
int read = inputStream.read(buffer.getByteBuffer().array());
if (read == -1)
break;
@ -125,48 +121,6 @@ public class IOResources
}
}
/**
* <p>Gets a {@link Content.Source} with the contents of a resource.</p>
* <p>The resource must not be a directory, must exists and there must be
* a way to access its contents.</p>
* <p>Multiple optimized methods are used to access the resource's contents but if they all fail,
* {@link Resource#newInputStream()} is used as a fallback.</p>
*
* @param resource the resource from which to get a {@link Content.Source}.
* @param bufferPool the {@link ByteBufferPool} to get buffers from. null means allocate new buffers as needed.
* @param bufferSize the size of the buffer to be used for the copy. Any value &lt; 1 means use a default value.
* @param direct the directness of the buffers, this parameter is ignored if {@code bufferSize} is &lt; 1.
* @return the {@link Content.Source}.
* @throws IllegalArgumentException if the resource is a directory or does not exist or there is no way to access its contents.
*/
public static Content.Source asContentSource(Resource resource, ByteBufferPool bufferPool, int bufferSize, boolean direct) throws IllegalArgumentException
{
if (resource.isDirectory() || !resource.exists())
throw new IllegalArgumentException("Resource must exist and cannot be a directory: " + resource);
// Try to find an optimized content source.
Path path = resource.getPath();
if (path != null)
{
return Content.Source.from(new ByteBufferPool.Sized(bufferPool, direct, bufferSize), path, 0, -1);
}
if (resource instanceof MemoryResource memoryResource)
{
byte[] bytes = memoryResource.getBytes();
return new ByteBufferContentSource(ByteBuffer.wrap(bytes));
}
// Fallback to wrapping InputStream.
try
{
return new InputStreamContentSource(resource.newInputStream());
}
catch (IOException e)
{
throw new RuntimeIOException(e);
}
}
/**
* <p>Gets a {@link Content.Source} with a range of the contents of a resource.</p>
* <p>The resource must not be a directory, must exists and there must be
@ -175,15 +129,13 @@ public class IOResources
* {@link Resource#newInputStream()} is used as a fallback.</p>
*
* @param resource the resource from which to get a {@link Content.Source}.
* @param bufferPool the {@link ByteBufferPool} to get buffers from. null means allocate new buffers as needed.
* @param bufferSize the size of the buffer to be used for the copy. Any value &lt; 1 means use a default value.
* @param direct the directness of the buffers, this parameter is ignored if {@code bufferSize} is &lt; 1.
* @param offset the first byte from which to read from.
* @param length the length of the content to read.
* @param bufferPool the {@link ByteBufferPool.Sized} to get buffers from. null means allocate new buffers as needed.
* @param offset the offset byte from which to read from.
* @param length the length of the content to read, -1 for the full length.
* @return the {@link Content.Source}.
* @throws IllegalArgumentException if the resource is a directory or does not exist or there is no way to access its contents.
*/
public static Content.Source asContentSource(Resource resource, ByteBufferPool bufferPool, int bufferSize, boolean direct, long offset, long length) throws IllegalArgumentException
public static Content.Source asContentSource(Resource resource, ByteBufferPool.Sized bufferPool, long offset, long length) throws IllegalArgumentException
{
if (resource.isDirectory() || !resource.exists())
throw new IllegalArgumentException("Resource must exist and cannot be a directory: " + resource);
@ -191,11 +143,11 @@ public class IOResources
// Try using the resource's path if possible, as the nio API is async and helps to avoid buffer copies.
Path path = resource.getPath();
if (path != null)
return Content.Source.from(new ByteBufferPool.Sized(bufferPool, direct, bufferSize), path, offset, length);
return Content.Source.from(bufferPool, path, offset, length);
// Try an optimization for MemoryResource.
if (resource instanceof MemoryResource memoryResource)
return Content.Source.from(ByteBuffer.wrap(memoryResource.getBytes()));
return Content.Source.from(BufferUtil.slice(ByteBuffer.wrap(memoryResource.getBytes()), (int)offset, (int)length));
// Fallback to InputStream.
try
@ -203,7 +155,7 @@ public class IOResources
InputStream inputStream = resource.newInputStream();
if (inputStream == null)
throw new IllegalArgumentException("Resource does not support InputStream: " + resource);
return Content.Source.from(new ByteBufferPool.Sized(bufferPool, direct, bufferSize), inputStream, offset, length);
return Content.Source.from(bufferPool, inputStream, offset, length);
}
catch (IOException e)
{
@ -236,72 +188,22 @@ public class IOResources
}
}
/**
* <p>Performs an asynchronous copy of the contents of a resource to a sink, using the given buffer pool and buffer characteristics.</p>
* <p>The resource must not be a directory, must exist and there must be a way to access its contents.</p>
* <p>Multiple optimized methods are used to access the resource's contents but if they all fail,
* {@link #asContentSource(Resource, ByteBufferPool, int, boolean)} is used as a fallback to perform the
* {@link Content#copy(Content.Source, Content.Sink, Callback) copy}.</p>
*
* @param resource the resource to copy from.
* @param sink the sink to copy to.
* @param bufferPool the {@link ByteBufferPool} to get buffers from. null means allocate new buffers as needed.
* @param bufferSize the size of the buffer to be used for the copy. Any value &lt; 1 means use a default value.
* @param direct the directness of the buffers, this parameter is ignored if {@code bufferSize} is &lt; 1.
* @param callback the callback to notify when the copy is done.
* @throws IllegalArgumentException if the resource is a directory or does not exist or there is no way to access its contents.
*/
public static void copy(Resource resource, Content.Sink sink, ByteBufferPool bufferPool, int bufferSize, boolean direct, Callback callback) throws IllegalArgumentException
{
try
{
if (resource.isDirectory() || !resource.exists())
throw new IllegalArgumentException("Resource must exist and cannot be a directory: " + resource);
// Save a Content.Source allocation for resources with a Path.
Path path = resource.getPath();
if (path != null)
{
new PathToSinkCopier(path, sink, bufferPool, bufferSize, direct, callback).iterate();
return;
}
// Directly write the byte array if the resource is a MemoryResource.
if (resource instanceof MemoryResource memoryResource)
{
byte[] bytes = memoryResource.getBytes();
sink.write(true, ByteBuffer.wrap(bytes), callback);
return;
}
// Fallback to Content.Source.
Content.Source source = asContentSource(resource, bufferPool, bufferSize, direct);
Content.copy(source, sink, callback);
}
catch (Throwable x)
{
callback.failed(x);
}
}
/**
* <p>Performs an asynchronous copy of a subset of the contents of a resource to a sink, using the given buffer pool and buffer characteristics.</p>
* <p>The resource must not be a directory, must exist and there must be a way to access its contents.</p>
* <p>Multiple optimized methods are used to access the resource's contents but if they all fail,
* {@link #asContentSource(Resource, ByteBufferPool, int, boolean, long, long)} is used as a fallback to perform the
* {@link #asContentSource(Resource, ByteBufferPool.Sized, long, long)} is used as a fallback to perform the
* {@link Content#copy(Content.Source, Content.Sink, Callback) copy}.</p>
*
* @param resource the resource to copy from.
* @param sink the sink to copy to.
* @param bufferPool the {@link ByteBufferPool} to get buffers from. null means allocate new buffers as needed.
* @param bufferSize the size of the buffer to be used for the copy. Any value &lt; 1 means use a default value.
* @param direct the directness of the buffers, this parameter is ignored if {@code bufferSize} is &lt; 1.
* @param first the first byte of the resource to start from.
* @param length the length of the resource's contents to copy.
* @param offset the offset byte of the resource to start from.
* @param length the length of the resource's contents to copy, -1 for the full length.
* @param callback the callback to notify when the copy is done.
* @throws IllegalArgumentException if the resource is a directory or does not exist or there is no way to access its contents.
*/
public static void copy(Resource resource, Content.Sink sink, ByteBufferPool bufferPool, int bufferSize, boolean direct, long first, long length, Callback callback) throws IllegalArgumentException
public static void copy(Resource resource, Content.Sink sink, ByteBufferPool.Sized bufferPool, long offset, long length, Callback callback) throws IllegalArgumentException
{
try
{
@ -312,20 +214,20 @@ public class IOResources
Path path = resource.getPath();
if (path != null)
{
new PathToSinkCopier(path, sink, bufferPool, bufferSize, direct, first, length, callback).iterate();
new PathToSinkCopier(path, sink, bufferPool, offset, length, callback).iterate();
return;
}
// Directly write the byte array if the resource is a MemoryResource.
if (resource instanceof MemoryResource memoryResource)
{
ByteBuffer byteBuffer = BufferUtil.slice(ByteBuffer.wrap(memoryResource.getBytes()), Math.toIntExact(first), Math.toIntExact(length));
ByteBuffer byteBuffer = BufferUtil.slice(ByteBuffer.wrap(memoryResource.getBytes()), Math.toIntExact(offset), Math.toIntExact(length));
sink.write(true, byteBuffer, callback);
return;
}
// Fallback to Content.Source.
Content.Source source = asContentSource(resource, bufferPool, bufferSize, direct, first, length);
Content.Source source = asContentSource(resource, bufferPool, offset, length);
Content.copy(source, sink, callback);
}
catch (Throwable x)
@ -338,35 +240,44 @@ public class IOResources
{
private final SeekableByteChannel channel;
private final Content.Sink sink;
private final ByteBufferPool pool;
private final int bufferSize;
private final boolean direct;
private final ByteBufferPool.Sized pool;
private long remainingLength;
private RetainableByteBuffer retainableByteBuffer;
private boolean terminated;
public PathToSinkCopier(Path path, Content.Sink sink, ByteBufferPool pool, int bufferSize, boolean direct, Callback callback) throws IOException
{
this(path, sink, pool, bufferSize, direct, -1L, -1L, callback);
}
public PathToSinkCopier(Path path, Content.Sink sink, ByteBufferPool pool, int bufferSize, boolean direct, long offset, long length, Callback callback) throws IOException
public PathToSinkCopier(Path path, Content.Sink sink, ByteBufferPool.Sized pool, long offset, long length, Callback callback) throws IOException
{
super(callback);
this.channel = Files.newByteChannel(path);
if (offset > -1)
{
if (offset > channel.size() && length != 0)
throw new IllegalArgumentException("Offset outside of Path range");
channel.position(offset);
}
this.sink = sink;
this.pool = pool == null ? ByteBufferPool.NON_POOLING : pool;
this.bufferSize = bufferSize <= 0 ? 4096 : bufferSize;
this.direct = direct;
this.pool = pool == null ? ByteBufferPool.SIZED_NON_POOLING : pool;
this.remainingLength = length;
this.channel = Files.newByteChannel(path);
skipToOffset(channel, offset, length, this.pool);
}
private static void skipToOffset(SeekableByteChannel channel, long offset, long length, ByteBufferPool.Sized pool)
{
if (offset > 0L && length != 0L)
{
RetainableByteBuffer.Mutable byteBuffer = pool.acquire(1);
try
{
channel.position(offset - 1);
if (channel.read(byteBuffer.getByteBuffer().limit(1)) == -1)
throw new IllegalArgumentException("Offset out of range");
}
catch (IOException e)
{
throw new RuntimeIOException(e);
}
finally
{
byteBuffer.release();
}
}
}
@Override
public InvocationType getInvocationType()
{
@ -380,7 +291,7 @@ public class IOResources
return Action.SUCCEEDED;
if (retainableByteBuffer == null)
retainableByteBuffer = pool.acquire(bufferSize, direct);
retainableByteBuffer = pool.acquire();
ByteBuffer byteBuffer = retainableByteBuffer.getByteBuffer();
BufferUtil.clearToFill(byteBuffer);

View File

@ -73,12 +73,12 @@ public class ByteChannelContentSource implements Content.Source
public ByteChannelContentSource(ByteChannel byteChannel)
{
this(null, byteChannel, -1L, -1L);
this(null, byteChannel, 0L, -1L);
}
public ByteChannelContentSource(ByteBufferPool.Sized byteBufferPool, ByteChannel byteChannel)
{
this(byteBufferPool, byteChannel, -1L, -1L);
this(byteBufferPool, byteChannel, 0L, -1L);
}
private ByteChannelContentSource(ByteBufferPool.Sized byteBufferPool, ByteChannel byteChannel, long offset, long length)
@ -253,17 +253,17 @@ public class ByteChannelContentSource implements Content.Source
public PathContentSource(Path path)
{
this(null, path, 0, -1);
this(null, path, 0L, -1L);
}
public PathContentSource(ByteBufferPool.Sized byteBufferPool, Path path)
{
this(byteBufferPool, path, 0, -1);
this(byteBufferPool, path, 0L, -1L);
}
public PathContentSource(ByteBufferPool.Sized byteBufferPool, Path path, long offset, long length)
{
super(byteBufferPool, null, offset, length < 0 ? size(path) : length);
super(byteBufferPool, null, offset, length < 0L ? size(path) : length);
_path = path;
}

View File

@ -34,25 +34,28 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
public class IOResourcesTest
{
private ArrayByteBufferPool.Tracking bufferPool;
private ArrayByteBufferPool.Tracking trackingPool;
private ByteBufferPool.Sized bufferPool;
@BeforeEach
public void setUp()
{
bufferPool = new ArrayByteBufferPool.Tracking();
trackingPool = new ArrayByteBufferPool.Tracking();
bufferPool = new ByteBufferPool.Sized(trackingPool, false, 1);
}
@AfterEach
public void tearDown()
{
assertThat("Leaks: " + bufferPool.dumpLeaks(), bufferPool.getLeaks().size(), is(0));
assertThat("Leaks: " + trackingPool.dumpLeaks(), trackingPool.getLeaks().size(), is(0));
}
public static Stream<Resource> all()
public static Stream<Resource> all() throws Exception
{
URI resourceUri = MavenTestingUtils.getTestResourcePath("keystore.p12").toUri();
return Stream.of(
ResourceFactory.root().newResource(resourceUri),
ResourceFactory.root().newMemoryResource(resourceUri.toURL()),
new URLResourceFactory().newResource(resourceUri)
);
}
@ -61,7 +64,7 @@ public class IOResourcesTest
@MethodSource("all")
public void testToRetainableByteBuffer(Resource resource)
{
RetainableByteBuffer retainableByteBuffer = IOResources.toRetainableByteBuffer(resource, bufferPool, false);
RetainableByteBuffer retainableByteBuffer = IOResources.toRetainableByteBuffer(resource, bufferPool);
assertThat(retainableByteBuffer.remaining(), is((int)resource.length()));
retainableByteBuffer.release();
}
@ -72,7 +75,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, 1, false);
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, 0L, -1L);
Content.copy(contentSource, sink, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
@ -87,7 +90,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, 1, false, 100, -1);
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, 100, -1);
Content.copy(contentSource, sink, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
@ -102,7 +105,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, 1, false, -1, 500);
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, -1, 500);
Content.copy(contentSource, sink, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
@ -117,7 +120,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, 1, false, 100, 500);
Content.Source contentSource = IOResources.asContentSource(resource, bufferPool, 100, 500);
Content.copy(contentSource, sink, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
@ -132,7 +135,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
IOResources.copy(resource, sink, bufferPool, 1, false, callback);
IOResources.copy(resource, sink, bufferPool, 0L, -1L, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
long sum = chunks.stream().mapToLong(Content.Chunk::remaining).sum();
@ -146,7 +149,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
IOResources.copy(resource, sink, bufferPool, 1, false, 100, -1, callback);
IOResources.copy(resource, sink, bufferPool, 100, -1, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
long sum = chunks.stream().mapToLong(Content.Chunk::remaining).sum();
@ -160,7 +163,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
IOResources.copy(resource, sink, bufferPool, 1, false, -1, 500, callback);
IOResources.copy(resource, sink, bufferPool, -1, 500, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
long sum = chunks.stream().mapToLong(Content.Chunk::remaining).sum();
@ -174,7 +177,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
IOResources.copy(resource, sink, bufferPool, 1, false, 100, 500, callback);
IOResources.copy(resource, sink, bufferPool, 100, 500, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
long sum = chunks.stream().mapToLong(Content.Chunk::remaining).sum();
@ -188,7 +191,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Blocker.Callback callback = Blocker.callback();
IOResources.copy(resource, sink, bufferPool, 1, false, Integer.MAX_VALUE, 1, callback);
IOResources.copy(resource, sink, bufferPool, Integer.MAX_VALUE, 1, callback);
assertThrows(IllegalArgumentException.class, callback::block);
}
@ -198,7 +201,7 @@ public class IOResourcesTest
{
TestSink sink = new TestSink();
Callback.Completable callback = new Callback.Completable();
IOResources.copy(resource, sink, bufferPool, 1, false, Integer.MAX_VALUE, 0, callback);
IOResources.copy(resource, sink, bufferPool, Integer.MAX_VALUE, 0, callback);
callback.get();
List<Content.Chunk> chunks = sink.takeAccumulatedChunks();
long sum = chunks.stream().mapToLong(Content.Chunk::remaining).sum();

View File

@ -298,7 +298,13 @@ public class BufferUtil
{
ByteBuffer slice = buffer.slice();
if (offset > 0)
slice.position(slice.position() + offset);
{
int newPosition = slice.position() + offset;
if (newPosition > slice.limit() && length == 0)
slice.position(slice.limit());
else
slice.position(newPosition);
}
if (length > -1)
slice.limit(slice.position() + length);
return slice;

View File

@ -68,6 +68,7 @@ public class BufferUtilTest
assertEquals("5678", BufferUtil.toString(BufferUtil.slice(byteBuffer, 5, 4)));
assertEquals("", BufferUtil.toString(BufferUtil.slice(byteBuffer, 1, 0)));
assertEquals("", BufferUtil.toString(BufferUtil.slice(byteBuffer, 10, -1)));
assertEquals("", BufferUtil.toString(BufferUtil.slice(byteBuffer, 1000, 0)));
assertThrows(IllegalArgumentException.class, () -> BufferUtil.slice(byteBuffer, 0, 11));
assertThrows(IllegalArgumentException.class, () -> BufferUtil.slice(byteBuffer, 11, -1));

View File

@ -134,7 +134,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
private long _written;
private long _flushed;
private long _firstByteNanoTime = -1;
private ByteBufferPool _pool;
private ByteBufferPool.Sized _pool;
private RetainableByteBuffer _aggregate;
private int _bufferSize;
private int _commitSize;
@ -580,17 +580,21 @@ public class HttpOutput extends ServletOutputStream implements Runnable
}
}
private ByteBufferPool.Sized getSizedByteBufferPool()
{
int bufferSize = getBufferSize();
boolean useOutputDirectByteBuffers = _servletChannel.getConnectionMetaData().getHttpConfiguration().isUseOutputDirectByteBuffers();
if (_pool == null || _pool.getSize() != bufferSize || _pool.isDirect() != useOutputDirectByteBuffers)
_pool = new ByteBufferPool.Sized(_servletChannel.getRequest().getComponents().getByteBufferPool(), useOutputDirectByteBuffers, bufferSize);
return _pool;
}
private RetainableByteBuffer lockedAcquireBuffer()
{
assert _channelState.isLockHeldByCurrentThread();
boolean useOutputDirectByteBuffers = _servletChannel.getConnectionMetaData().getHttpConfiguration().isUseOutputDirectByteBuffers();
if (_aggregate == null)
{
_pool = _servletChannel.getRequest().getComponents().getByteBufferPool();
_aggregate = _pool.acquire(getBufferSize(), useOutputDirectByteBuffers);
}
_aggregate = getSizedByteBufferPool().acquire();
return _aggregate;
}

View File

@ -185,6 +185,7 @@ public class ResourceServlet extends HttpServlet
private ServletResourceService _resourceService;
private WelcomeServletMode _welcomeServletMode;
private boolean _pathInfoOnly;
private ByteBufferPool.Sized _bufferPool;
public ResourceService getResourceService()
{
@ -225,9 +226,8 @@ public class ResourceServlet extends HttpServlet
if (contentFactory == null)
{
MimeTypes mimeTypes = contextHandler.getMimeTypes();
ByteBufferPool bufferPool = getByteBufferPool(contextHandler);
ByteBufferPool.Sized sizedBufferPool = new ByteBufferPool.Sized(bufferPool, getInitBoolean("useDirectByteBuffers", true), getInitInt("byteBufferSize", 32768));
contentFactory = new ResourceHttpContentFactory(baseResource, mimeTypes, sizedBufferPool);
ByteBufferPool.Sized bufferPool = getByteBufferPool(contextHandler);
contentFactory = new ResourceHttpContentFactory(baseResource, mimeTypes, bufferPool);
// Use the servers default stylesheet unless there is one explicitly set by an init param.
Resource styleSheet = contextHandler.getServer().getDefaultStyleSheet();
@ -255,7 +255,7 @@ public class ResourceServlet extends HttpServlet
if (getInitBoolean("useFileMappedBuffer", false))
contentFactory = new FileMappingHttpContentFactory(contentFactory);
contentFactory = new VirtualHttpContentFactory(contentFactory, styleSheet, "text/css", sizedBufferPool);
contentFactory = new VirtualHttpContentFactory(contentFactory, styleSheet, "text/css", bufferPool);
contentFactory = new PreCompressedHttpContentFactory(contentFactory, precompressedFormats);
int maxCacheSize = getInitInt("maxCacheSize", -2);
@ -337,14 +337,17 @@ public class ResourceServlet extends HttpServlet
}
}
private static ByteBufferPool getByteBufferPool(ContextHandler contextHandler)
private ByteBufferPool.Sized getByteBufferPool(ContextHandler contextHandler)
{
if (_bufferPool != null)
return _bufferPool;
if (contextHandler == null)
return ByteBufferPool.NON_POOLING;
return ByteBufferPool.SIZED_NON_POOLING;
Server server = contextHandler.getServer();
if (server == null)
return ByteBufferPool.NON_POOLING;
return server.getByteBufferPool();
return ByteBufferPool.SIZED_NON_POOLING;
_bufferPool = new ByteBufferPool.Sized(server.getByteBufferPool(), getInitBoolean("useDirectByteBuffers", true), getInitInt("byteBufferSize", 32768));
return _bufferPool;
}
private String getInitParameter(String name, String... deprecated)

View File

@ -134,6 +134,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
private long _written;
private long _flushed;
private long _firstByteNanoTime = -1;
private ByteBufferPool.Sized _pool;
private RetainableByteBuffer _aggregate;
private int _bufferSize;
private int _commitSize;
@ -221,7 +222,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
_state = State.CLOSED;
closedCallback = _closedCallback;
_closedCallback = null;
releaseBuffer();
lockedReleaseBuffer(failure != null);
wake = updateApiState(failure);
}
else if (_state == State.CLOSE)
@ -327,7 +328,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
// TODO avoid this copy.
ByteBuffer content = _aggregate != null && _aggregate.hasRemaining() ? BufferUtil.copy(_aggregate.getByteBuffer()) : BufferUtil.EMPTY_BUFFER;
_state = State.CLOSED;
releaseBuffer();
lockedReleaseBuffer(false);
return content;
}
}
@ -457,7 +458,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
try (AutoLock ignored = _channelState.lock())
{
_state = State.CLOSED;
releaseBuffer();
lockedReleaseBuffer(failure != null);
}
}
@ -589,25 +590,40 @@ public class HttpOutput extends ServletOutputStream implements Runnable
{
try (AutoLock ignored = _channelState.lock())
{
return acquireBuffer().getByteBuffer();
return lockedAcquireBuffer().getByteBuffer();
}
}
private RetainableByteBuffer acquireBuffer()
private ByteBufferPool.Sized getSizedByteBufferPool()
{
int bufferSize = getBufferSize();
boolean useOutputDirectByteBuffers = _servletChannel.getConnectionMetaData().getHttpConfiguration().isUseOutputDirectByteBuffers();
ByteBufferPool pool = _servletChannel.getRequest().getComponents().getByteBufferPool();
if (_pool == null || _pool.getSize() != bufferSize || _pool.isDirect() != useOutputDirectByteBuffers)
_pool = new ByteBufferPool.Sized(_servletChannel.getRequest().getComponents().getByteBufferPool(), useOutputDirectByteBuffers, bufferSize);
return _pool;
}
private RetainableByteBuffer lockedAcquireBuffer()
{
assert _channelState.isLockHeldByCurrentThread();
if (_aggregate == null)
_aggregate = pool.acquire(getBufferSize(), useOutputDirectByteBuffers);
_aggregate = getSizedByteBufferPool().acquire();
return _aggregate;
}
private void releaseBuffer()
private void lockedReleaseBuffer(boolean failure)
{
assert _channelState.isLockHeldByCurrentThread();
if (_aggregate != null)
{
_aggregate.release();
if (failure && _pool != null)
_pool.removeAndRelease(_aggregate);
else
_aggregate.release();
_aggregate = null;
_pool = null;
}
}
@ -765,7 +781,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
// Should we aggregate?
if (aggregate)
{
acquireBuffer();
lockedAcquireBuffer();
int filled = BufferUtil.fill(_aggregate.getByteBuffer(), b, off, len);
// return if we are not complete, not full and filled all the content
@ -970,7 +986,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
}
_written = written;
acquireBuffer();
lockedAcquireBuffer();
BufferUtil.append(_aggregate.getByteBuffer(), (byte)b);
}
@ -1249,6 +1265,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
{
try (AutoLock ignored = _channelState.lock())
{
lockedReleaseBuffer(_state != State.CLOSED);
_state = State.OPEN;
_apiState = ApiState.BLOCKING;
_softClose = true; // Stay closed until next request
@ -1257,7 +1274,6 @@ public class HttpOutput extends ServletOutputStream implements Runnable
_commitSize = config.getOutputAggregationSize();
if (_commitSize > _bufferSize)
_commitSize = _bufferSize;
releaseBuffer();
_written = 0;
_writeListener = null;
_onError = null;

View File

@ -185,6 +185,7 @@ public class ResourceServlet extends HttpServlet
private ServletResourceService _resourceService;
private WelcomeServletMode _welcomeServletMode;
private boolean _pathInfoOnly;
private ByteBufferPool.Sized _bufferPool;
public ResourceService getResourceService()
{
@ -225,9 +226,8 @@ public class ResourceServlet extends HttpServlet
if (contentFactory == null)
{
MimeTypes mimeTypes = contextHandler.getMimeTypes();
ByteBufferPool bufferPool = getByteBufferPool(contextHandler);
ByteBufferPool.Sized sizedBufferPool = new ByteBufferPool.Sized(bufferPool, getInitBoolean("useDirectByteBuffers", true), getInitInt("byteBufferSize", 32768));
contentFactory = new ResourceHttpContentFactory(baseResource, mimeTypes, sizedBufferPool);
ByteBufferPool.Sized bufferPool = new ByteBufferPool.Sized(getByteBufferPool(contextHandler), getInitBoolean("useDirectByteBuffers", true), getInitInt("byteBufferSize", 32768));
contentFactory = new ResourceHttpContentFactory(baseResource, mimeTypes, bufferPool);
// Use the servers default stylesheet unless there is one explicitly set by an init param.
Resource styleSheet = contextHandler.getServer().getDefaultStyleSheet();
@ -255,7 +255,7 @@ public class ResourceServlet extends HttpServlet
if (getInitBoolean("useFileMappedBuffer", false))
contentFactory = new FileMappingHttpContentFactory(contentFactory);
contentFactory = new VirtualHttpContentFactory(contentFactory, styleSheet, "text/css", sizedBufferPool);
contentFactory = new VirtualHttpContentFactory(contentFactory, styleSheet, "text/css", bufferPool);
contentFactory = new PreCompressedHttpContentFactory(contentFactory, precompressedFormats);
int maxCacheSize = getInitInt("maxCacheSize", -2);
@ -337,14 +337,17 @@ public class ResourceServlet extends HttpServlet
}
}
private static ByteBufferPool getByteBufferPool(ContextHandler contextHandler)
private ByteBufferPool.Sized getByteBufferPool(ContextHandler contextHandler)
{
if (_bufferPool != null)
return _bufferPool;
if (contextHandler == null)
return ByteBufferPool.NON_POOLING;
return ByteBufferPool.SIZED_NON_POOLING;
Server server = contextHandler.getServer();
if (server == null)
return ByteBufferPool.NON_POOLING;
return server.getByteBufferPool();
return ByteBufferPool.SIZED_NON_POOLING;
_bufferPool = new ByteBufferPool.Sized(server.getByteBufferPool(), getInitBoolean("useDirectByteBuffers", true), getInitInt("byteBufferSize", 32768));
return _bufferPool;
}
private String getInitParameter(String name, String... deprecated)

View File

@ -224,6 +224,11 @@ public class ServletChannelState
return _lock.lock();
}
boolean isLockHeldByCurrentThread()
{
return _lock.isHeldByCurrentThread();
}
public State getState()
{
try (AutoLock ignored = lock())

View File

@ -198,7 +198,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
private long _written;
private long _flushed;
private long _firstByteNanoTime = -1;
private ByteBufferPool _pool;
private ByteBufferPool.Sized _pool;
private RetainableByteBuffer _aggregate;
private int _bufferSize;
private int _commitSize;
@ -654,15 +654,21 @@ public class HttpOutput extends ServletOutputStream implements Runnable
}
}
private ByteBufferPool.Sized getSizedByteBufferPool()
{
int bufferSize = getBufferSize();
boolean useOutputDirectByteBuffers = _channel.isUseOutputDirectByteBuffers();
if (_pool == null || _pool.getSize() != bufferSize || _pool.isDirect() != useOutputDirectByteBuffers)
_pool = new ByteBufferPool.Sized(_channel.getByteBufferPool(), useOutputDirectByteBuffers, bufferSize);
return _pool;
}
private RetainableByteBuffer lockedAcquireBuffer()
{
assert _channelState.isLockHeldByCurrentThread();
if (_aggregate == null)
{
_pool = _channel.getByteBufferPool();
_aggregate = _pool.acquire(getBufferSize(), _channel.isUseOutputDirectByteBuffers());
}
_aggregate = getSizedByteBufferPool().acquire();
return _aggregate;
}
@ -1319,7 +1325,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
{
_written += byteBuffer.remaining();
channelWrite(byteBuffer, last, cb);
}, _channel.getByteBufferPool(), getBufferSize(), _channel.isUseOutputDirectByteBuffers(), new Callback.Nested(callback)
}, getSizedByteBufferPool(), 0L, -1L, new Callback.Nested(callback)
{
@Override
public void succeeded()

View File

@ -32,6 +32,7 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.IOResources;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.LocalConnector;
@ -235,7 +236,7 @@ public class HttpOutputTest
public void testSendBigDirect() throws Exception
{
Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._content = IOResources.toRetainableByteBuffer(big, null, true).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
assertThat(response, containsString("HTTP/1.1 200 OK"));
assertThat(response, containsString("Content-Length"));
@ -246,7 +247,7 @@ public class HttpOutputTest
public void testSendBigInDirect() throws Exception
{
Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
assertThat(response, containsString("HTTP/1.1 200 OK"));
assertThat(response, containsString("Content-Length"));
@ -311,7 +312,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[1];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -325,7 +326,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[8];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -339,7 +340,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[4000];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -353,7 +354,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[8192];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -367,7 +368,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[1];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -382,7 +383,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[8];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -397,7 +398,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[4000];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -412,7 +413,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[8192];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -445,7 +446,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(8);
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -460,7 +461,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(4000);
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -475,7 +476,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(8192);
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -490,7 +491,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(8);
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -505,7 +506,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(4000);
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -520,7 +521,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(8192);
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -535,7 +536,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[1];
_handler._async = true;
@ -551,7 +552,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[8];
_handler._async = true;
@ -567,7 +568,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[4000];
_handler._async = true;
@ -583,7 +584,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[8192];
_handler._async = true;
@ -618,7 +619,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(8);
_handler._async = true;
@ -634,7 +635,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(4000);
_handler._async = true;
@ -650,7 +651,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(8192);
_handler._async = true;
@ -667,7 +668,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, true).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, new ByteBufferPool.Sized(ByteBufferPool.SIZED_NON_POOLING, true, ByteBufferPool.SIZED_NON_POOLING.getSize())).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocateDirect(8192);
_handler._async = true;
@ -683,7 +684,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._byteBuffer = BufferUtil.allocate(8192);
_handler._async = true;
@ -703,7 +704,7 @@ public class HttpOutputTest
_handler._async = true;
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[4000];
String response = _connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n");
@ -720,7 +721,7 @@ public class HttpOutputTest
_handler._async = true;
_handler._writeLengthIfKnown = true;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[4000];
int start = _handler._owp.get();
@ -736,7 +737,7 @@ public class HttpOutputTest
{
final Resource big = ResourceFactory.of(_contextHandler).newClassPathResource("simple/big.txt");
_handler._writeLengthIfKnown = false;
_handler._content = IOResources.toRetainableByteBuffer(big, null, false).getByteBuffer();
_handler._content = IOResources.toRetainableByteBuffer(big, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer();
_handler._arrayBuffer = new byte[1024];
_handler._interceptor = new ChainedInterceptor()
{
@ -1194,7 +1195,7 @@ public class HttpOutputTest
private static String toUTF8String(Resource resource)
{
return BufferUtil.toUTF8String(IOResources.toRetainableByteBuffer(resource, null, false).getByteBuffer());
return BufferUtil.toUTF8String(IOResources.toRetainableByteBuffer(resource, ByteBufferPool.SIZED_NON_POOLING).getByteBuffer());
}
interface ChainedInterceptor extends HttpOutput.Interceptor

View File

@ -259,9 +259,8 @@ public class DefaultServlet extends HttpServlet implements WelcomeFactory
HttpContent.Factory contentFactory = (HttpContent.Factory)getServletContext().getAttribute(HttpContent.Factory.class.getName());
if (contentFactory == null)
{
ByteBufferPool bufferPool = getByteBufferPool(_contextHandler);
ByteBufferPool.Sized sizedBufferPool = new ByteBufferPool.Sized(bufferPool, getInitBoolean("useDirectByteBuffers", true), getInitInt("byteBufferSize", 32768));
contentFactory = new ResourceHttpContentFactory(_baseResource, _mimeTypes, sizedBufferPool)
ByteBufferPool.Sized bufferPool = new ByteBufferPool.Sized(getByteBufferPool(_contextHandler), getInitBoolean("useDirectByteBuffers", true), getInitInt("byteBufferSize", 32768));
contentFactory = new ResourceHttpContentFactory(_baseResource, _mimeTypes, bufferPool)
{
@Override
protected Resource resolve(String pathInContext)
@ -271,7 +270,7 @@ public class DefaultServlet extends HttpServlet implements WelcomeFactory
};
if (_useFileMappedBuffer)
contentFactory = new FileMappingHttpContentFactory(contentFactory);
contentFactory = new VirtualHttpContentFactory(contentFactory, _styleSheet, "text/css", sizedBufferPool);
contentFactory = new VirtualHttpContentFactory(contentFactory, _styleSheet, "text/css", bufferPool);
contentFactory = new PreCompressedHttpContentFactory(contentFactory, _resourceService.getPrecompressedFormats());
int maxCacheSize = getInitInt("maxCacheSize", -2);