Skip to content

Commit 73e6058

Browse files
authored
Partial fix for #12681 caching content (#12702)
This is a partial fix for #12681. It does not fix the actual release race on a single content, but by restricting the shrinking to a single thread, make the race less likely to occur. There is a more comprehensive fix in #12678 and #12704 for 12.1,
1 parent 0a23b82 commit 73e6058

File tree

1 file changed

+37
-25
lines changed

1 file changed

+37
-25
lines changed

jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/CachingHttpContentFactory.java

+37-25
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
6868
private final HttpContent.Factory _authority;
6969
private final ConcurrentHashMap<String, CachingHttpContent> _cache = new ConcurrentHashMap<>();
7070
private final AtomicLong _cachedSize = new AtomicLong();
71+
private final AtomicBoolean _shrinking = new AtomicBoolean();
7172
private final ByteBufferPool _bufferPool;
7273
private int _maxCachedFileSize = DEFAULT_MAX_CACHED_FILE_SIZE;
7374
private int _maxCachedFiles = DEFAULT_MAX_CACHED_FILES;
@@ -148,35 +149,46 @@ public void setUseDirectByteBuffers(boolean useDirectByteBuffers)
148149

149150
private void shrinkCache()
150151
{
151-
// While we need to shrink
152-
int numCacheEntries = _cache.size();
153-
while (numCacheEntries > 0 && (numCacheEntries > _maxCachedFiles || _cachedSize.get() > _maxCacheSize))
152+
// Only 1 thread shrinking at once
153+
if (_shrinking.compareAndSet(false, true))
154154
{
155-
// Scan the entire cache and generate an ordered list by last accessed time.
156-
SortedSet<CachingHttpContent> sorted = new TreeSet<>((c1, c2) ->
155+
try
157156
{
158-
long delta = NanoTime.elapsed(c2.getLastAccessedNanos(), c1.getLastAccessedNanos());
159-
if (delta != 0)
160-
return delta < 0 ? -1 : 1;
161-
162-
delta = c1.getContentLengthValue() - c2.getContentLengthValue();
163-
if (delta != 0)
164-
return delta < 0 ? -1 : 1;
165-
166-
return c1.getKey().compareTo(c2.getKey());
167-
});
168-
sorted.addAll(_cache.values());
169-
170-
// TODO: Can we remove the buffers from the content before evicting.
171-
// Invalidate least recently used first
172-
for (CachingHttpContent content : sorted)
157+
// While we need to shrink
158+
int numCacheEntries = _cache.size();
159+
while (numCacheEntries > 0 && (numCacheEntries > _maxCachedFiles || _cachedSize.get() > _maxCacheSize))
160+
{
161+
// Scan the entire cache and generate an ordered list by last accessed time.
162+
SortedSet<CachingHttpContent> sorted = new TreeSet<>((c1, c2) ->
163+
{
164+
long delta = NanoTime.elapsed(c2.getLastAccessedNanos(), c1.getLastAccessedNanos());
165+
if (delta != 0)
166+
return delta < 0 ? -1 : 1;
167+
168+
delta = c1.getContentLengthValue() - c2.getContentLengthValue();
169+
if (delta != 0)
170+
return delta < 0 ? -1 : 1;
171+
172+
return c1.getKey().compareTo(c2.getKey());
173+
});
174+
sorted.addAll(_cache.values());
175+
176+
// TODO: Can we remove the buffers from the content before evicting.
177+
// Invalidate least recently used first
178+
for (CachingHttpContent content : sorted)
179+
{
180+
if (_cache.size() <= _maxCachedFiles && _cachedSize.get() <= _maxCacheSize)
181+
break;
182+
removeFromCache(content);
183+
}
184+
185+
numCacheEntries = _cache.size();
186+
}
187+
}
188+
finally
173189
{
174-
if (_cache.size() <= _maxCachedFiles && _cachedSize.get() <= _maxCacheSize)
175-
break;
176-
removeFromCache(content);
190+
_shrinking.set(false);
177191
}
178-
179-
numCacheEntries = _cache.size();
180192
}
181193
}
182194

0 commit comments

Comments
 (0)