From d906d374b8aae2238bd3fe2324d3ed998677508f Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Sat, 2 Jan 2021 01:29:46 -0800 Subject: [PATCH] Optimize getAllPresent methods This restores an optimization that was removed in #176 due to a bug in Java 8. --- .../caffeine/cache/BoundedLocalCache.java | 21 +++++++++---------- .../caffeine/cache/LocalAsyncCache.java | 20 +++++++++--------- .../caffeine/cache/LocalLoadingCache.java | 20 +++++++++--------- .../caffeine/cache/UnboundedLocalCache.java | 19 ++++++++--------- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java index 6b5cc97002..b16e03adee 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java @@ -43,7 +43,6 @@ import java.util.Comparator; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -1916,33 +1915,33 @@ public boolean containsValue(Object value) { @Override public Map getAllPresent(Iterable keys) { - Set uniqueKeys = new LinkedHashSet<>(); + Map result = new LinkedHashMap<>(); for (Object key : keys) { - uniqueKeys.add(key); + result.put(key, null); } - int misses = 0; + int uniqueKeys = result.size(); long now = expirationTicker().read(); - Map result = new LinkedHashMap<>(uniqueKeys.size()); - for (Object key : uniqueKeys) { + for (var iter = result.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = iter.next(); V value; - Node node = data.get(nodeFactory.newLookupKey(key)); + Node node = data.get(nodeFactory.newLookupKey(entry.getKey())); if ((node == null) || ((value = node.getValue()) == null) || hasExpired(node, now)) { - misses++; + iter.remove(); } else { - result.put(key, value); + entry.setValue(value); if (!isComputingAsync(node)) { @SuppressWarnings("unchecked") - K castedKey = (K) key; + K castedKey = (K) entry.getKey(); tryExpireAfterRead(node, castedKey, value, expiry(), now); setAccessTime(node, now); } afterRead(node, now, /* recordHit */ false); } } - statsCounter().recordMisses(misses); statsCounter().recordHits(result.size()); + statsCounter().recordMisses(uniqueKeys - result.size()); @SuppressWarnings("unchecked") Map castedResult = (Map) result; diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java index 18b57f6167..e6f5b27894 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java @@ -28,7 +28,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; @@ -474,24 +473,25 @@ abstract class AbstractCacheView implements Cache, Serializable { @Override public Map getAllPresent(Iterable keys) { - Set uniqueKeys = new LinkedHashSet<>(); + Map result = new LinkedHashMap<>(); for (Object key : keys) { - uniqueKeys.add(key); + result.put(key, null); } - int misses = 0; - Map result = new LinkedHashMap<>(); - for (Object key : uniqueKeys) { - CompletableFuture future = asyncCache().cache().get(key); + int uniqueKeys = result.size(); + for (var iter = result.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = iter.next(); + + CompletableFuture future = asyncCache().cache().get(entry.getKey()); Object value = Async.getIfReady(future); if (value == null) { - misses++; + iter.remove(); } else { - result.put(key, value); + entry.setValue(value); } } - asyncCache().cache().statsCounter().recordMisses(misses); asyncCache().cache().statsCounter().recordHits(result.size()); + asyncCache().cache().statsCounter().recordMisses(uniqueKeys - result.size()); @SuppressWarnings("unchecked") Map castedResult = (Map) result; diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java index b1192d294c..5e12bdf397 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java @@ -22,9 +22,7 @@ import java.lang.reflect.Method; import java.util.Collections; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.Map; -import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.function.Function; @@ -64,24 +62,26 @@ default Map getAll(Iterable keys) { /** Sequentially loads each missing entry. */ default Map loadSequentially(Iterable keys) { - Set uniqueKeys = new LinkedHashSet<>(); + Map result = new LinkedHashMap<>(); for (K key : keys) { - uniqueKeys.add(key); + result.put(key, null); } int count = 0; - Map result = new LinkedHashMap<>(uniqueKeys.size()); try { - for (K key : uniqueKeys) { + for (var iter = result.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = iter.next(); count++; - V value = get(key); - if (value != null) { - result.put(key, value); + V value = get(entry.getKey()); + if (value == null) { + iter.remove(); + } else { + entry.setValue(value); } } } catch (Throwable t) { - cache().statsCounter().recordMisses(uniqueKeys.size() - count); + cache().statsCounter().recordMisses(result.size() - count); throw t; } return Collections.unmodifiableMap(result); diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/UnboundedLocalCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/UnboundedLocalCache.java index c8ba128bfd..065d394c9c 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/UnboundedLocalCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/UnboundedLocalCache.java @@ -28,7 +28,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -110,23 +109,23 @@ public long estimatedSize() { @Override public Map getAllPresent(Iterable keys) { - Set uniqueKeys = new LinkedHashSet<>(); + Map result = new LinkedHashMap<>(); for (Object key : keys) { - uniqueKeys.add(key); + result.put(key, null); } - int misses = 0; - Map result = new LinkedHashMap<>(uniqueKeys.size()); - for (Object key : uniqueKeys) { - Object value = data.get(key); + int uniqueKeys = result.size(); + for (var iter = result.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = iter.next(); + Object value = data.get(entry.getKey()); if (value == null) { - misses++; + iter.remove(); } else { - result.put(key, value); + entry.setValue(value); } } - statsCounter.recordMisses(misses); statsCounter.recordHits(result.size()); + statsCounter.recordMisses(uniqueKeys - result.size()); @SuppressWarnings("unchecked") Map castedResult = (Map) result;