changes from review
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
7bb3fcae03
commit
489da47a38
|
@ -15,6 +15,7 @@ package org.eclipse.jetty.http;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
@ -22,11 +23,11 @@ import java.util.TreeSet;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.NoopByteBufferPool;
|
||||
import org.eclipse.jetty.io.Retainable;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -44,19 +45,30 @@ import org.slf4j.LoggerFactory;
|
|||
* assumed to be valid. This class can be extended to implement the validation behaviours on
|
||||
* {@link CachingHttpContent} which allow entries to be evicted once they become invalid.
|
||||
* </p>
|
||||
* <p><br>
|
||||
* The default values for the cache are:
|
||||
* <ul>
|
||||
* <li>maxCachedFileSize: {@value #DEFAULT_MAX_CACHE_SIZE}</li>
|
||||
* <li>maxCachedFiles: {@value #DEFAULT_MAX_CACHED_FILES}</li>
|
||||
* <li>maxCacheSize: {@value #DEFAULT_MAX_CACHE_SIZE}</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* @see ValidatingCachingContentFactory
|
||||
*/
|
||||
public class CachingHttpContentFactory implements HttpContent.Factory
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CachingHttpContentFactory.class);
|
||||
private static final int DEFAULT_MAX_CACHED_FILE_SIZE = 128 * 1024 * 1024;
|
||||
private static final int DEFAULT_MAX_CACHED_FILES = 2048;
|
||||
private static final int DEFAULT_MAX_CACHE_SIZE = 256 * 1024 * 1024;
|
||||
|
||||
private final HttpContent.Factory _authority;
|
||||
private final ConcurrentMap<String, CachingHttpContent> _cache = new ConcurrentHashMap<>();
|
||||
private final AtomicLong _cachedSize = new AtomicLong();
|
||||
private final ByteBufferPool _byteBufferPool;
|
||||
private int _maxCachedFileSize = 128 * 1024 * 1024;
|
||||
private int _maxCachedFiles = 2048;
|
||||
private int _maxCacheSize = 256 * 1024 * 1024;
|
||||
private int _maxCachedFileSize = DEFAULT_MAX_CACHED_FILE_SIZE;
|
||||
private int _maxCachedFiles = DEFAULT_MAX_CACHED_FILES;
|
||||
private int _maxCacheSize = DEFAULT_MAX_CACHE_SIZE;
|
||||
|
||||
public CachingHttpContentFactory(HttpContent.Factory authority, ByteBufferPool byteBufferPool)
|
||||
{
|
||||
|
@ -257,7 +269,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
private final String _cacheKey;
|
||||
private final HttpField _etagField;
|
||||
private final long _contentLengthValue;
|
||||
private final AtomicLong _lastAccessed = new AtomicLong();
|
||||
private volatile long _lastAccessed;
|
||||
private final Set<CompressedContentFormat> _compressedFormats;
|
||||
private final String _lastModifiedValue;
|
||||
private final String _characterEncoding;
|
||||
|
@ -265,7 +277,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
private final HttpField _contentLength;
|
||||
private final Instant _lastModifiedInstant;
|
||||
private final HttpField _lastModified;
|
||||
private final AtomicInteger _referenceCount = new AtomicInteger(1);
|
||||
private final Retainable.ReferenceCounter _referenceCount = new Retainable.ReferenceCounter();
|
||||
|
||||
public CachedHttpContent(String key, HttpContent httpContent)
|
||||
{
|
||||
|
@ -291,7 +303,10 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
if (contentLengthValue > _maxCachedFileSize)
|
||||
{
|
||||
byteBuffer = _byteBufferPool.acquire((int)contentLengthValue, false);
|
||||
BufferUtil.readFrom(httpContent.getResource().newReadableByteChannel(), contentLengthValue, byteBuffer);
|
||||
try (ReadableByteChannel readableByteChannel = httpContent.getResource().newReadableByteChannel())
|
||||
{
|
||||
BufferUtil.readFrom(readableByteChannel, contentLengthValue, byteBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
|
@ -315,7 +330,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
_lastModifiedInstant = httpContent.getLastModifiedInstant();
|
||||
_lastModified = httpContent.getLastModified();
|
||||
|
||||
_lastAccessed.set(NanoTime.now());
|
||||
_lastAccessed = NanoTime.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -333,13 +348,13 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
@Override
|
||||
public long getLastAccessedNanos()
|
||||
{
|
||||
return _lastAccessed.get();
|
||||
return _lastAccessed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastAccessedNanos(long nanosTime)
|
||||
{
|
||||
_lastAccessed.set(nanosTime);
|
||||
_lastAccessed = nanosTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -351,13 +366,13 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
@Override
|
||||
public void retain()
|
||||
{
|
||||
_referenceCount.incrementAndGet();
|
||||
_referenceCount.retain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release()
|
||||
{
|
||||
if (_referenceCount.decrementAndGet() == 0)
|
||||
if (_referenceCount.release())
|
||||
{
|
||||
if (_buffer != null)
|
||||
_byteBufferPool.release(_buffer);
|
||||
|
@ -428,14 +443,14 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
|
||||
protected static class NotFoundHttpContent implements CachingHttpContent
|
||||
{
|
||||
private final AtomicLong _lastAccessed = new AtomicLong();
|
||||
private volatile long _lastAccessed;
|
||||
|
||||
private final String _key;
|
||||
|
||||
public NotFoundHttpContent(String key)
|
||||
{
|
||||
_key = key;
|
||||
_lastAccessed.set(NanoTime.now());
|
||||
_lastAccessed = NanoTime.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -447,13 +462,13 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
@Override
|
||||
public long getLastAccessedNanos()
|
||||
{
|
||||
return _lastAccessed.get();
|
||||
return _lastAccessed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastAccessedNanos(long nanosTime)
|
||||
{
|
||||
_lastAccessed.set(nanosTime);
|
||||
_lastAccessed = nanosTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,15 +25,29 @@ import org.slf4j.LoggerFactory;
|
|||
public class FileMappedHttpContentFactory implements HttpContent.Factory
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FileMappedHttpContentFactory.class);
|
||||
private static final int DEFAULT_MIN_FILE_SIZE = 16 * 1024;
|
||||
|
||||
private final HttpContent.Factory _factory;
|
||||
private final int _minFileSize;
|
||||
|
||||
/**
|
||||
* Construct a {@link FileMappedHttpContentFactory} which can use file mapped buffers.
|
||||
* Uses a default value of {@value DEFAULT_MIN_FILE_SIZE} for the minimum size of an
|
||||
* {@link HttpContent} before trying to use a file mapped buffer.
|
||||
*
|
||||
* @param factory the wrapped {@link HttpContent.Factory} to use.
|
||||
*/
|
||||
public FileMappedHttpContentFactory(HttpContent.Factory factory)
|
||||
{
|
||||
this(factory, 16 * 1024);
|
||||
this(factory, DEFAULT_MIN_FILE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link FileMappedHttpContentFactory} which can use file mapped buffers.
|
||||
*
|
||||
* @param factory the wrapped {@link HttpContent.Factory} to use.
|
||||
* @param minFileSize the minimum size of an {@link HttpContent} before trying to use a file mapped buffer.
|
||||
*/
|
||||
public FileMappedHttpContentFactory(HttpContent.Factory factory, int minFileSize)
|
||||
{
|
||||
_factory = Objects.requireNonNull(factory);
|
||||
|
@ -49,7 +63,7 @@ public class FileMappedHttpContentFactory implements HttpContent.Factory
|
|||
return content;
|
||||
}
|
||||
|
||||
public static class FileMappedContent extends HttpContentWrapper
|
||||
private static class FileMappedContent extends HttpContentWrapper
|
||||
{
|
||||
private final AutoLock _lock = new AutoLock();
|
||||
private final HttpContent _content;
|
||||
|
|
|
@ -38,7 +38,7 @@ public class RetainableByteBuffer extends Retainable.ReferenceCounter
|
|||
private final Consumer<RetainableByteBuffer> releaser;
|
||||
private final AtomicLong lastUpdate = new AtomicLong(NanoTime.now());
|
||||
|
||||
public RetainableByteBuffer(ByteBuffer buffer, Consumer<RetainableByteBuffer> releaser)
|
||||
RetainableByteBuffer(ByteBuffer buffer, Consumer<RetainableByteBuffer> releaser)
|
||||
{
|
||||
super(0);
|
||||
this.releaser = releaser;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -595,14 +596,32 @@ public class BufferUtil
|
|||
}
|
||||
}
|
||||
|
||||
public static void readFrom(ReadableByteChannel newReadableByteChannel, long contentLengthValue, ByteBuffer byteBuffer) throws IOException
|
||||
/**
|
||||
* Read content from a {@link ReadableByteChannel} into a buffer.
|
||||
* This may spin if {@link ReadableByteChannel#read(ByteBuffer)} returns 0 in which case this
|
||||
* will call {@link Thread#onSpinWait()}.
|
||||
*
|
||||
* @param readableByteChannel the channel to read from.
|
||||
* @param contentLengthValue the length of the content to read.
|
||||
* @param byteBuffer the buffer to read into.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public static void readFrom(ReadableByteChannel readableByteChannel, long contentLengthValue, ByteBuffer byteBuffer) throws IOException
|
||||
{
|
||||
int pos = BufferUtil.flipToFill(byteBuffer);
|
||||
try (ReadableByteChannel channel = newReadableByteChannel)
|
||||
try
|
||||
{
|
||||
int read = 0;
|
||||
while (read != contentLengthValue)
|
||||
read += channel.read(byteBuffer);
|
||||
int totalRead = 0;
|
||||
while (totalRead != contentLengthValue)
|
||||
{
|
||||
int read = readableByteChannel.read(byteBuffer);
|
||||
if (read == 0)
|
||||
Thread.onSpinWait();
|
||||
else if (read < 0)
|
||||
throw new EOFException();
|
||||
else
|
||||
totalRead += read;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue