diff --git a/server/src/main/java/org/elasticsearch/common/cache/Cache.java b/server/src/main/java/org/elasticsearch/common/cache/Cache.java index 98a4b90da73d5..e380375a29de5 100644 --- a/server/src/main/java/org/elasticsearch/common/cache/Cache.java +++ b/server/src/main/java/org/elasticsearch/common/cache/Cache.java @@ -8,7 +8,6 @@ package org.elasticsearch.common.cache; -import org.elasticsearch.common.util.concurrent.ReleasableLock; import org.elasticsearch.core.Tuple; import java.lang.reflect.Array; @@ -19,6 +18,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.LongAdder; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -178,10 +178,10 @@ private static final class Entry { */ private final class CacheSegment { // read/write lock protecting mutations to the segment - ReadWriteLock segmentLock = new ReentrantReadWriteLock(); + final ReadWriteLock segmentLock = new ReentrantReadWriteLock(); - ReleasableLock readLock = new ReleasableLock(segmentLock.readLock()); - ReleasableLock writeLock = new ReleasableLock(segmentLock.writeLock()); + final Lock readLock = segmentLock.readLock(); + final Lock writeLock = segmentLock.writeLock(); Map>> map; @@ -196,8 +196,11 @@ private final class CacheSegment { */ Entry get(K key, long now, boolean eagerEvict) { CompletableFuture> future; - try (ReleasableLock ignored = readLock.acquire()) { + readLock.lock(); + try { future = map == null ? null : map.get(key); + } finally { + readLock.unlock(); } if (future != null) { Entry entry; @@ -213,8 +216,11 @@ Entry get(K key, long now, boolean eagerEvict) { if (isExpired(entry, now)) { misses.increment(); if (eagerEvict) { - try (ReleasableLock ignored = lruLock.acquire()) { + lruLock.lock(); + try { evictEntry(entry); + } finally { + lruLock.unlock(); } } return null; @@ -240,7 +246,8 @@ Entry get(K key, long now, boolean eagerEvict) { Tuple, Entry> put(K key, V value, long now) { Entry entry = new Entry<>(key, value, now); Entry existing = null; - try (ReleasableLock ignored = writeLock.acquire()) { + writeLock.lock(); + try { try { if (map == null) { map = new HashMap<>(); @@ -252,6 +259,8 @@ Tuple, Entry> put(K key, V value, long now) { } catch (ExecutionException | InterruptedException e) { throw new IllegalStateException(e); } + } finally { + writeLock.unlock(); } return Tuple.tuple(entry, existing); } @@ -263,7 +272,8 @@ Tuple, Entry> put(K key, V value, long now) { */ void remove(K key) { CompletableFuture> future; - try (ReleasableLock ignored = writeLock.acquire()) { + writeLock.lock(); + try { if (map == null) { future = null; } else { @@ -272,6 +282,8 @@ void remove(K key) { map = null; } } + } finally { + writeLock.unlock(); } if (future != null) { evictions.increment(); @@ -290,7 +302,8 @@ void remove(K key) { void remove(K key, V value, boolean notify) { CompletableFuture> future; boolean removed = false; - try (ReleasableLock ignored = writeLock.acquire()) { + writeLock.lock(); + try { future = map == null ? null : map.get(key); try { if (future != null) { @@ -307,6 +320,8 @@ void remove(K key, V value, boolean notify) { } catch (ExecutionException | InterruptedException e) { throw new IllegalStateException(e); } + } finally { + writeLock.unlock(); } if (future != null && removed) { @@ -333,7 +348,7 @@ void remove(K key, V value, boolean notify) { Entry tail; // lock protecting mutations to the LRU list - private final ReleasableLock lruLock = new ReleasableLock(new ReentrantLock()); + private final ReentrantLock lruLock = new ReentrantLock(); /** * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. @@ -380,15 +395,18 @@ public V computeIfAbsent(K key, CacheLoader loader) throws ExecutionExcept // need a mechanism to ensure that load is invoked at most once, but we are not invoking load while holding // the segment lock; to do this, we atomically put a future in the map that can load the value, and then // get the value from this future on the thread that won the race to place the future into the segment map - CacheSegment segment = getCacheSegment(key); + final CacheSegment segment = getCacheSegment(key); CompletableFuture> future; CompletableFuture> completableFuture = new CompletableFuture<>(); - try (ReleasableLock ignored = segment.writeLock.acquire()) { + segment.writeLock.lock(); + try { if (segment.map == null) { segment.map = new HashMap<>(); } future = segment.map.putIfAbsent(key, completableFuture); + } finally { + segment.writeLock.unlock(); } BiFunction, Throwable, ? extends V> handler = (ok, ex) -> { @@ -396,7 +414,8 @@ public V computeIfAbsent(K key, CacheLoader loader) throws ExecutionExcept promote(ok, now); return ok.value; } else { - try (ReleasableLock ignored = segment.writeLock.acquire()) { + segment.writeLock.lock(); + try { CompletableFuture> sanity = segment.map == null ? null : segment.map.get(key); if (sanity != null && sanity.isCompletedExceptionally()) { segment.map.remove(key); @@ -404,6 +423,8 @@ public V computeIfAbsent(K key, CacheLoader loader) throws ExecutionExcept segment.map = null; } } + } finally { + segment.writeLock.unlock(); } return null; } @@ -461,13 +482,16 @@ private void put(K key, V value, long now) { CacheSegment segment = getCacheSegment(key); Tuple, Entry> tuple = segment.put(key, value, now); boolean replaced = false; - try (ReleasableLock ignored = lruLock.acquire()) { + lruLock.lock(); + try { if (tuple.v2() != null && tuple.v2().state == State.EXISTING) { if (unlink(tuple.v2())) { replaced = true; } } promote(tuple.v1(), now); + } finally { + lruLock.unlock(); } if (replaced) { removalListener.onRemoval( @@ -479,8 +503,11 @@ private void put(K key, V value, long now) { private void notifyWithInvalidated(CompletableFuture> f) { try { Entry entry = f.get(); - try (ReleasableLock ignored = lruLock.acquire()) { + lruLock.lock(); + try { delete(entry, RemovalNotification.RemovalReason.INVALIDATED); + } finally { + lruLock.unlock(); } } catch (ExecutionException e) { // ok @@ -521,7 +548,8 @@ public void invalidateAll() { Entry h; boolean[] haveSegmentLock = new boolean[NUMBER_OF_SEGMENTS]; - try (ReleasableLock ignored = lruLock.acquire()) { + lruLock.lock(); + try { try { for (int i = 0; i < NUMBER_OF_SEGMENTS; i++) { segments[i].segmentLock.writeLock().lock(); @@ -546,6 +574,8 @@ public void invalidateAll() { } } } + } finally { + lruLock.unlock(); } while (h != null) { removalListener.onRemoval(new RemovalNotification<>(h.key, h.value, RemovalNotification.RemovalReason.INVALIDATED)); @@ -558,8 +588,11 @@ public void invalidateAll() { */ public void refresh() { long now = now(); - try (ReleasableLock ignored = lruLock.acquire()) { + lruLock.lock(); + try { evict(now); + } finally { + lruLock.unlock(); } } @@ -589,7 +622,7 @@ public long weight() { * @return an LRU-ordered {@link Iterable} over the keys in the cache */ public Iterable keys() { - return () -> new Iterator() { + return () -> new Iterator<>() { private final CacheIterator iterator = new CacheIterator(head); @Override @@ -617,7 +650,7 @@ public void remove() { * @return an LRU-ordered {@link Iterable} over the values in the cache */ public Iterable values() { - return () -> new Iterator() { + return () -> new Iterator<>() { private final CacheIterator iterator = new CacheIterator(head); @Override @@ -647,7 +680,8 @@ public void remove() { */ public void forEach(BiConsumer consumer) { for (CacheSegment segment : segments) { - try (ReleasableLock ignored = segment.readLock.acquire()) { + segment.readLock.lock(); + try { if (segment.map == null) { continue; } @@ -661,6 +695,8 @@ public void forEach(BiConsumer consumer) { throw new IllegalStateException(e); } } + } finally { + segment.readLock.unlock(); } } } @@ -692,9 +728,12 @@ public void remove() { if (entry != null) { CacheSegment segment = getCacheSegment(entry.key); segment.remove(entry.key, entry.value, false); - try (ReleasableLock ignored = lruLock.acquire()) { + lruLock.lock(); + try { current = null; delete(entry, RemovalNotification.RemovalReason.INVALIDATED); + } finally { + lruLock.unlock(); } } } @@ -736,7 +775,8 @@ public long getEvictions() { private void promote(Entry entry, long now) { boolean promoted = true; - try (ReleasableLock ignored = lruLock.acquire()) { + lruLock.lock(); + try { switch (entry.state) { case DELETED -> promoted = false; case EXISTING -> relinkAtHead(entry); @@ -745,6 +785,8 @@ private void promote(Entry entry, long now) { if (promoted) { evict(now); } + } finally { + lruLock.unlock(); } }