fix stampede creating CachingHttpContent & remove usage of getPreCompressedContentFormats
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
a7383ea4de
commit
6a6681a2df
|
@ -16,12 +16,12 @@ package org.eclipse.jetty.http;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
|
@ -171,7 +171,7 @@ public class CachingContentFactory implements HttpContent.ContentFactory
|
|||
return false;
|
||||
if (httpContent instanceof MappedFileContentFactory.FileMappedContent)
|
||||
return true;
|
||||
return ((len <= _maxCachedFileSize) && (len + getCachedSize() <= _maxCacheSize));
|
||||
return (len <= _maxCachedFileSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -186,21 +186,21 @@ public class CachingContentFactory implements HttpContent.ContentFactory
|
|||
removeFromCache(cachingHttpContent);
|
||||
}
|
||||
|
||||
// TODO: record cache misses.
|
||||
HttpContent httpContent = _authority.getContent(path);
|
||||
if (isCacheable(httpContent))
|
||||
{
|
||||
cachingHttpContent = new CachingHttpContent(path, httpContent);
|
||||
httpContent = _cache.putIfAbsent(path, cachingHttpContent);
|
||||
if (httpContent != null)
|
||||
AtomicBoolean wasAdded = new AtomicBoolean(false);
|
||||
cachingHttpContent = _cache.computeIfAbsent(path, p ->
|
||||
{
|
||||
cachingHttpContent.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
httpContent = cachingHttpContent;
|
||||
_cachedSize.addAndGet(cachingHttpContent.getContentLengthValue());
|
||||
wasAdded.set(true);
|
||||
_cachedSize.addAndGet(httpContent.getContentLengthValue());
|
||||
return new CachingHttpContent(p, httpContent);
|
||||
});
|
||||
|
||||
if (wasAdded.get())
|
||||
shrinkCache();
|
||||
}
|
||||
return cachingHttpContent;
|
||||
}
|
||||
return httpContent;
|
||||
}
|
||||
|
@ -212,15 +212,14 @@ public class CachingContentFactory implements HttpContent.ContentFactory
|
|||
private final String _cacheKey;
|
||||
private final HttpField _etagField;
|
||||
private final long _contentLengthValue;
|
||||
private final Set<CompressedContentFormat> _precompressedContents;
|
||||
private final AtomicLong _lastAccessed = new AtomicLong();
|
||||
|
||||
private CachingHttpContent(String key, HttpContent httpContent) throws IOException
|
||||
private CachingHttpContent(String key, HttpContent httpContent)
|
||||
{
|
||||
this(key, httpContent, httpContent.getETagValue());
|
||||
}
|
||||
|
||||
private CachingHttpContent(String key, HttpContent httpContent, String etagValue) throws IOException
|
||||
private CachingHttpContent(String key, HttpContent httpContent, String etagValue)
|
||||
{
|
||||
super(httpContent);
|
||||
|
||||
|
@ -239,6 +238,7 @@ public class CachingContentFactory implements HttpContent.ContentFactory
|
|||
if (resourceSize < 0)
|
||||
throw new IllegalArgumentException("Resource with negative size: " + _delegate.getResource());
|
||||
|
||||
// TODO: do all the following lazily and asynchronously.
|
||||
HttpField etagField = _delegate.getETag();
|
||||
if (StringUtil.isNotBlank(etagValue))
|
||||
{
|
||||
|
@ -252,7 +252,6 @@ public class CachingContentFactory implements HttpContent.ContentFactory
|
|||
_cacheKey = key;
|
||||
_lastModifiedValue = _delegate.getResource().lastModified();
|
||||
_lastAccessed.set(NanoTime.now());
|
||||
_precompressedContents = _delegate.getPreCompressedContentFormats();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -307,11 +306,5 @@ public class CachingContentFactory implements HttpContent.ContentFactory
|
|||
return null;
|
||||
return etag.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompressedContentFormat> getPreCompressedContentFormats()
|
||||
{
|
||||
return _precompressedContents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ public class ResourceHttpContent implements HttpContent
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{r=%s,ct=%s,c=%b}", this.getClass().getSimpleName(), hashCode(), _resource, _contentType, _precompressedContents != null);
|
||||
return String.format("%s@%x{r=%s,ct=%s}", this.getClass().getSimpleName(), hashCode(), _resource, _contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,10 +23,8 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jetty.http.ByteRange;
|
||||
|
@ -109,33 +107,32 @@ public class ResourceService
|
|||
HttpContent content = _contentFactory.getContent(path == null ? "" : path);
|
||||
if (content != null)
|
||||
{
|
||||
Set<CompressedContentFormat> preCompressedContentFormats = content.getPreCompressedContentFormats();
|
||||
if (!preCompressedContentFormats.isEmpty())
|
||||
{
|
||||
HashSet<CompressedContentFormat> availableFormats = new HashSet<>(preCompressedContentFormats);
|
||||
availableFormats.retainAll(_precompressedFormats);
|
||||
|
||||
for (String encoding : getPreferredEncodingOrder(request))
|
||||
{
|
||||
CompressedContentFormat contentFormat = isEncodingAvailable(encoding, availableFormats);
|
||||
if (contentFormat == null)
|
||||
continue;
|
||||
|
||||
HttpContent preCompressedContent = _contentFactory.getContent(path + contentFormat.getExtension());
|
||||
if (preCompressedContent == null)
|
||||
continue;
|
||||
|
||||
AliasCheck aliasCheck = ContextHandler.getContextHandler(request);
|
||||
if (aliasCheck != null && !aliasCheck.checkAlias(path, content.getResource()))
|
||||
return null;
|
||||
|
||||
return new PrecompressedHttpContent(content, preCompressedContent, contentFormat);
|
||||
}
|
||||
}
|
||||
|
||||
AliasCheck aliasCheck = ContextHandler.getContextHandler(request);
|
||||
if (aliasCheck != null && !aliasCheck.checkAlias(path, content.getResource()))
|
||||
return null;
|
||||
|
||||
if (!_precompressedFormats.isEmpty())
|
||||
{
|
||||
List<String> preferredEncodingOrder = getPreferredEncodingOrder(request);
|
||||
if (!preferredEncodingOrder.isEmpty())
|
||||
{
|
||||
for (String encoding : preferredEncodingOrder)
|
||||
{
|
||||
CompressedContentFormat contentFormat = isEncodingAvailable(encoding, _precompressedFormats);
|
||||
if (contentFormat == null)
|
||||
continue;
|
||||
|
||||
HttpContent preCompressedContent = _contentFactory.getContent(path + contentFormat.getExtension());
|
||||
if (preCompressedContent == null)
|
||||
continue;
|
||||
|
||||
if (aliasCheck != null && !aliasCheck.checkAlias(path, preCompressedContent.getResource()))
|
||||
return null;
|
||||
|
||||
return new PrecompressedHttpContent(content, preCompressedContent, contentFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1526,6 +1526,9 @@ public class ResourceHandlerTest
|
|||
while (Files.getLastModifiedTime(tempPath).equals(before));
|
||||
long newExpectedSize = Files.size(tempPath);
|
||||
|
||||
// The cached Resource will only go to fileSystem for expiryTime once per second.
|
||||
Thread.sleep(1100);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
|
@ -1941,6 +1944,9 @@ public class ResourceHandlerTest
|
|||
}
|
||||
while (Files.getLastModifiedTime(testFile).equals(before));
|
||||
|
||||
// The cached Resource will only go to fileSystem for expiryTime once per second.
|
||||
Thread.sleep(1100);
|
||||
|
||||
response = HttpTester.parseResponse(
|
||||
_local.getResponse("""
|
||||
GET /context/test-etag-file.txt HTTP/1.1\r
|
||||
|
|
|
@ -15,8 +15,6 @@ package org.eclipse.jetty.ee9.nested;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
|
@ -69,7 +67,6 @@ public class ResourceContentFactory implements ContentFactory
|
|||
}
|
||||
|
||||
private HttpContent load(String pathInContext, Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if (resource == null || !resource.exists())
|
||||
return null;
|
||||
|
@ -77,25 +74,7 @@ public class ResourceContentFactory implements ContentFactory
|
|||
if (resource.isDirectory())
|
||||
return new ResourceHttpContent(resource, _mimeTypes.getMimeByExtension(resource.toString()));
|
||||
|
||||
// Look for a precompressed resource or content
|
||||
String mt = _mimeTypes.getMimeByExtension(pathInContext);
|
||||
if (_precompressedFormats.length > 0)
|
||||
{
|
||||
// Is there a compressed resource?
|
||||
Map<CompressedContentFormat, HttpContent> compressedContents = new HashMap<>(_precompressedFormats.length);
|
||||
for (CompressedContentFormat format : _precompressedFormats)
|
||||
{
|
||||
String compressedPathInContext = pathInContext + format.getExtension();
|
||||
Resource compressedResource = _factory.newResource(compressedPathInContext);
|
||||
if (compressedResource != null && compressedResource.exists() && ResourceContentFactory.newerThanOrEqual(compressedResource, resource) &&
|
||||
compressedResource.length() < resource.length())
|
||||
compressedContents.put(format,
|
||||
new ResourceHttpContent(compressedResource, _mimeTypes.getMimeByExtension(compressedPathInContext)));
|
||||
}
|
||||
if (!compressedContents.isEmpty())
|
||||
return new ResourceHttpContent(resource, mt, compressedContents);
|
||||
}
|
||||
return new ResourceHttpContent(resource, mt);
|
||||
return new ResourceHttpContent(resource, _mimeTypes.getMimeByExtension(pathInContext));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue