changes from review
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
af19607f1c
commit
e28a528165
|
@ -34,9 +34,16 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@link HttpContent.Factory} implementation that wraps any other {@link HttpContent.Factory} instance
|
||||
* using it as a caching authority.
|
||||
* Only HttpContent instances whose path is not a directory are cached.
|
||||
* using it as a caching authority. Only HttpContent instances whose path is not a directory are cached.
|
||||
* </p>
|
||||
* <p>
|
||||
* No eviction is done by this {@link HttpContent.Factory}, once an entry is in the cache it is always
|
||||
* 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>
|
||||
* @see ValidatingCachingContentFactory
|
||||
*/
|
||||
public class CachingHttpContentFactory implements HttpContent.Factory
|
||||
{
|
||||
|
@ -118,7 +125,8 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
private void shrinkCache()
|
||||
{
|
||||
// While we need to shrink
|
||||
while (_cache.size() > 0 && (_cache.size() > _maxCachedFiles || _cachedSize.get() > _maxCacheSize))
|
||||
int numCacheEntries = _cache.size();
|
||||
while (numCacheEntries > 0 && (numCacheEntries > _maxCachedFiles || _cachedSize.get() > _maxCacheSize))
|
||||
{
|
||||
// Scan the entire cache and generate an ordered list by last accessed time.
|
||||
SortedSet<CachingHttpContent> sorted = new TreeSet<>((c1, c2) ->
|
||||
|
@ -143,6 +151,8 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
break;
|
||||
removeFromCache(content);
|
||||
}
|
||||
|
||||
numCacheEntries = _cache.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,21 +282,24 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
}
|
||||
_etagField = etagField;
|
||||
|
||||
// Map the content into memory if possible.
|
||||
RetainableByteBuffer buffer = null;
|
||||
try
|
||||
// Read the content into memory if the HttpContent does not already have a buffer.
|
||||
RetainableByteBuffer buffer = httpContent.getBuffer();
|
||||
if (buffer != null)
|
||||
{
|
||||
long contentLengthValue = getContentLengthValue();
|
||||
if (contentLengthValue > _maxCachedFileSize)
|
||||
try
|
||||
{
|
||||
buffer = _byteBufferPool.acquire((int)contentLengthValue, false);
|
||||
BufferUtil.readFrom(httpContent.getResource().newReadableByteChannel(), contentLengthValue, buffer.getBuffer());
|
||||
long contentLengthValue = getContentLengthValue();
|
||||
if (contentLengthValue > _maxCachedFileSize)
|
||||
{
|
||||
buffer = _byteBufferPool.acquire((int)contentLengthValue, false);
|
||||
BufferUtil.readFrom(httpContent.getResource().newReadableByteChannel(), contentLengthValue, buffer.getBuffer());
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
buffer = null;
|
||||
LOG.warn("Failed to read Resource", t);
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
buffer = null;
|
||||
LOG.warn("Failed to read Resource", t);
|
||||
}
|
||||
_buffer = buffer;
|
||||
|
||||
|
@ -335,6 +348,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
|
|||
@Override
|
||||
public void release()
|
||||
{
|
||||
super.release();
|
||||
if (_buffer != null)
|
||||
_buffer.release();
|
||||
}
|
||||
|
|
|
@ -41,24 +41,41 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
* elapsed the entry will be invalid and will be evicted from the cache at the next access.
|
||||
* </p>
|
||||
*/
|
||||
public class EvictingCachingContentFactory extends CachingHttpContentFactory implements Runnable
|
||||
public class ValidatingCachingContentFactory extends CachingHttpContentFactory implements Runnable
|
||||
{
|
||||
private final Scheduler _scheduler;
|
||||
private final long _sweepDelay;
|
||||
private final long _validationTime;
|
||||
private final long _maxCacheIdleTime;
|
||||
|
||||
public EvictingCachingContentFactory(@Name("authority") HttpContent.Factory authority,
|
||||
@Name("validationTime") long validationTime)
|
||||
/**
|
||||
* Construct a {@link ValidatingCachingContentFactory} which validates entries upon use to check if they
|
||||
* are still valid.
|
||||
*
|
||||
* @param authority the wrapped {@link HttpContent.Factory} to use.
|
||||
* @param validationTime time between filesystem checks in ms to see if an {@link HttpContent} is still valid (-1 never validate, 0 always validate).
|
||||
*/
|
||||
public ValidatingCachingContentFactory(@Name("authority") HttpContent.Factory authority,
|
||||
@Name("validationTime") long validationTime)
|
||||
{
|
||||
this(authority, validationTime, null, -1, -1);
|
||||
}
|
||||
|
||||
public EvictingCachingContentFactory(@Name("authority") HttpContent.Factory authority,
|
||||
@Name("validationTime") long validationTime,
|
||||
@Name("scheduler") Scheduler scheduler,
|
||||
@Name("sweepDelay") long sweepDelay,
|
||||
@Name("maxCacheIdleTime") long maxCacheIdleTime)
|
||||
/**
|
||||
* Construct a {@link ValidatingCachingContentFactory} which validates entries upon use to check if they
|
||||
* are still valid and an optional period sweeper of the cache to find invalid and old entries to evict.
|
||||
*
|
||||
* @param authority the wrapped {@link HttpContent.Factory} to use.
|
||||
* @param validationTime time between filesystem checks in ms to see if an {@link HttpContent} is still valid (-1 never validate, 0 always validate).
|
||||
* @param scheduler scheduler to use for the sweeper, can be null to not use sweeper.
|
||||
* @param sweepDelay time between runs of the sweeper in ms (if < 0 never sweep for invalid entries).
|
||||
* @param maxCacheIdleTime amount of time in ms an entry can be unused before evicted by the sweeper (if < 0 never evict unused entries).
|
||||
*/
|
||||
public ValidatingCachingContentFactory(@Name("authority") HttpContent.Factory authority,
|
||||
@Name("validationTime") long validationTime,
|
||||
@Name("scheduler") Scheduler scheduler,
|
||||
@Name("sweepDelay") long sweepDelay,
|
||||
@Name("maxCacheIdleTime") long maxCacheIdleTime)
|
||||
{
|
||||
super(authority);
|
||||
_validationTime = validationTime;
|
||||
|
@ -85,36 +102,42 @@ public class EvictingCachingContentFactory extends CachingHttpContentFactory imp
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
ConcurrentMap<String, CachingHttpContent> cache = getCache();
|
||||
for (Map.Entry<String, CachingHttpContent> entry : cache.entrySet())
|
||||
try
|
||||
{
|
||||
CachingHttpContent value = entry.getValue();
|
||||
if (_maxCacheIdleTime > 0 && NanoTime.since(value.getLastAccessedNanos()) > TimeUnit.MILLISECONDS.toNanos(_maxCacheIdleTime))
|
||||
removeFromCache(value);
|
||||
else if (!value.isValid())
|
||||
removeFromCache(value);
|
||||
ConcurrentMap<String, CachingHttpContent> cache = getCache();
|
||||
for (Map.Entry<String, CachingHttpContent> entry : cache.entrySet())
|
||||
{
|
||||
CachingHttpContent value = entry.getValue();
|
||||
if (_maxCacheIdleTime > 0 && NanoTime.since(value.getLastAccessedNanos()) > TimeUnit.MILLISECONDS.toNanos(_maxCacheIdleTime))
|
||||
removeFromCache(value);
|
||||
else if (!value.isValid())
|
||||
removeFromCache(value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
schedule();
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CachingHttpContent newCachedContent(String p, HttpContent httpContent)
|
||||
{
|
||||
return new EvictingCachedContent(p, httpContent, _validationTime);
|
||||
return new ValidatingCachedContent(p, httpContent, _validationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CachingHttpContent newNotFoundContent(String p)
|
||||
{
|
||||
return new EvictingNotFoundContent(p, _validationTime);
|
||||
return new ValidatingNotFoundContent(p, _validationTime);
|
||||
}
|
||||
|
||||
protected class EvictingCachedContent extends CachedHttpContent
|
||||
protected class ValidatingCachedContent extends CachedHttpContent
|
||||
{
|
||||
private final long _validationTime;
|
||||
private final AtomicLong _lastValidated = new AtomicLong();
|
||||
|
||||
public EvictingCachedContent(String key, HttpContent httpContent, long validationTime)
|
||||
public ValidatingCachedContent(String key, HttpContent httpContent, long validationTime)
|
||||
{
|
||||
super(key, httpContent);
|
||||
_lastValidated.set(NanoTime.now());
|
||||
|
@ -140,12 +163,12 @@ public class EvictingCachingContentFactory extends CachingHttpContentFactory imp
|
|||
}
|
||||
}
|
||||
|
||||
protected static class EvictingNotFoundContent extends NotFoundHttpContent
|
||||
protected static class ValidatingNotFoundContent extends NotFoundHttpContent
|
||||
{
|
||||
private final long _validationTime;
|
||||
private final AtomicLong _lastValidated = new AtomicLong();
|
||||
|
||||
public EvictingNotFoundContent(String key, long validationTime)
|
||||
public ValidatingNotFoundContent(String key, long validationTime)
|
||||
{
|
||||
super(key);
|
||||
_validationTime = validationTime;
|
|
@ -17,13 +17,13 @@ import java.time.Duration;
|
|||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.EvictingCachingContentFactory;
|
||||
import org.eclipse.jetty.http.FileMappedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PreCompressedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.ResourceHttpContentFactory;
|
||||
import org.eclipse.jetty.http.ValidatingCachingContentFactory;
|
||||
import org.eclipse.jetty.server.Context;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
@ -88,7 +88,7 @@ public class ResourceHandler extends Handler.Wrapper
|
|||
HttpContent.Factory contentFactory = new ResourceHttpContentFactory(ResourceFactory.of(_resourceBase), _mimeTypes);
|
||||
contentFactory = new PreCompressedHttpContentFactory(contentFactory, _resourceService.getPrecompressedFormats());
|
||||
contentFactory = new FileMappedHttpContentFactory(contentFactory);
|
||||
contentFactory = new EvictingCachingContentFactory(contentFactory, Duration.ofSeconds(1).toMillis());
|
||||
contentFactory = new ValidatingCachingContentFactory(contentFactory, Duration.ofSeconds(1).toMillis());
|
||||
return contentFactory;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ import org.eclipse.jetty.http.CachingHttpContentFactory;
|
|||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.DateGenerator;
|
||||
import org.eclipse.jetty.http.EtagUtils;
|
||||
import org.eclipse.jetty.http.EvictingCachingContentFactory;
|
||||
import org.eclipse.jetty.http.FileMappedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
|
@ -48,6 +47,7 @@ import org.eclipse.jetty.http.HttpTester;
|
|||
import org.eclipse.jetty.http.PreCompressedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.ResourceHttpContentFactory;
|
||||
import org.eclipse.jetty.http.UriCompliance;
|
||||
import org.eclipse.jetty.http.ValidatingCachingContentFactory;
|
||||
import org.eclipse.jetty.logging.StacklessLogging;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
|
@ -669,7 +669,7 @@ public class ResourceHandlerTest
|
|||
HttpContent.Factory contentFactory = new ResourceHttpContentFactory(ResourceFactory.of(getBaseResource()), getMimeTypes());
|
||||
contentFactory = new PreCompressedHttpContentFactory(contentFactory, getPrecompressedFormats());
|
||||
contentFactory = new FileMappedHttpContentFactory(contentFactory);
|
||||
contentFactory = new EvictingCachingContentFactory(contentFactory, 0);
|
||||
contentFactory = new ValidatingCachingContentFactory(contentFactory, 0);
|
||||
return contentFactory;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -45,7 +45,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||
import jakarta.servlet.http.HttpServletResponseWrapper;
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.EvictingCachingContentFactory;
|
||||
import org.eclipse.jetty.http.FileMappedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpContentWrapper;
|
||||
|
@ -59,6 +58,7 @@ import org.eclipse.jetty.http.MetaData;
|
|||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PreCompressedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.ResourceHttpContentFactory;
|
||||
import org.eclipse.jetty.http.ValidatingCachingContentFactory;
|
||||
import org.eclipse.jetty.io.ByteBufferInputStream;
|
||||
import org.eclipse.jetty.io.Content;
|
||||
import org.eclipse.jetty.server.Components;
|
||||
|
@ -144,7 +144,7 @@ public class DefaultServlet extends HttpServlet
|
|||
long cacheValidationTime = getInitParameter("cacheValidationTime") != null ? Long.parseLong(getInitParameter("cacheValidationTime")) : -2;
|
||||
if (maxCachedFiles != -2 || maxCacheSize != -2 || maxCachedFileSize != -2 || cacheValidationTime != -2)
|
||||
{
|
||||
EvictingCachingContentFactory cached = new EvictingCachingContentFactory(contentFactory,
|
||||
ValidatingCachingContentFactory cached = new ValidatingCachingContentFactory(contentFactory,
|
||||
(cacheValidationTime > -2) ? cacheValidationTime : Duration.ofSeconds(1).toMillis());
|
||||
contentFactory = cached;
|
||||
if (maxCacheSize >= 0)
|
||||
|
|
|
@ -25,7 +25,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.ee9.nested.ContextHandler.APIContext;
|
||||
import org.eclipse.jetty.ee9.nested.ResourceService.WelcomeFactory;
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.EvictingCachingContentFactory;
|
||||
import org.eclipse.jetty.http.FileMappedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -34,6 +33,7 @@ import org.eclipse.jetty.http.MimeTypes;
|
|||
import org.eclipse.jetty.http.PreCompressedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http.ResourceHttpContentFactory;
|
||||
import org.eclipse.jetty.http.ValidatingCachingContentFactory;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
@ -112,7 +112,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,
|
|||
HttpContent.Factory contentFactory = new ResourceHttpContentFactory(this, _mimeTypes);
|
||||
contentFactory = new PreCompressedHttpContentFactory(contentFactory, _resourceService.getPrecompressedFormats());
|
||||
contentFactory = new FileMappedHttpContentFactory(contentFactory);
|
||||
contentFactory = new EvictingCachingContentFactory(contentFactory, Duration.ofSeconds(1).toMillis());
|
||||
contentFactory = new ValidatingCachingContentFactory(contentFactory, Duration.ofSeconds(1).toMillis());
|
||||
return contentFactory;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ import org.eclipse.jetty.ee9.nested.ResourceService;
|
|||
import org.eclipse.jetty.ee9.nested.ResourceService.WelcomeFactory;
|
||||
import org.eclipse.jetty.http.CachingHttpContentFactory;
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.EvictingCachingContentFactory;
|
||||
import org.eclipse.jetty.http.FileMappedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -40,6 +39,7 @@ import org.eclipse.jetty.http.MimeTypes;
|
|||
import org.eclipse.jetty.http.PreCompressedHttpContentFactory;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http.ResourceHttpContentFactory;
|
||||
import org.eclipse.jetty.http.ValidatingCachingContentFactory;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -257,7 +257,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
|
|||
long cacheValidationTime = getInitParameter("cacheValidationTime") != null ? Long.parseLong(getInitParameter("cacheValidationTime")) : -2;
|
||||
if (maxCachedFiles != -2 || maxCacheSize != -2 || maxCachedFileSize != -2 || cacheValidationTime != -2)
|
||||
{
|
||||
_cachingContentFactory = new EvictingCachingContentFactory(contentFactory,
|
||||
_cachingContentFactory = new ValidatingCachingContentFactory(contentFactory,
|
||||
(cacheValidationTime > -2) ? cacheValidationTime : Duration.ofSeconds(1).toMillis());
|
||||
contentFactory = _cachingContentFactory;
|
||||
if (maxCacheSize >= 0)
|
||||
|
|
Loading…
Reference in New Issue