@Override public boolean contains(Object obj) { if (!(obj instanceof Entry<?, ?>)) { return false; } Entry<?, ?> entry = (Entry<?, ?>) obj; Node<K, V> node = cache.data.get(cache.nodeFactory.newLookupKey(entry.getKey())); return (node != null) && Objects.equals(node.getValue(), entry.getValue()); }
/** Returns if the node's value is currently being computed, asynchronously. */ final boolean isComputingAsync(Node<?, ?> node) { return isAsync && !Async.isReady((CompletableFuture<?>) node.getValue()); }
Node<K, V> node = iterator.next(); K key = node.getKey(); V value = transformer.apply(node.getValue()); if ((key != null) && (value != null) && node.isAlive()) { map.put(key, value);
@Override public boolean hasNext() { if (next != null) { return true; } for (;;) { if (iterator.hasNext()) { next = iterator.next(); value = next.getValue(); key = next.getKey(); if (cache.hasExpired(next, now) || (key == null) || (value == null) || !next.isAlive()) { value = null; next = null; key = null; continue; } return true; } return false; } }
@Override public boolean containsKey(Object key) { Node<K, V> node = data.get(nodeFactory.newLookupKey(key)); return (node != null) && (node.getValue() != null) && !hasExpired(node, expirationTicker().read()); }
@Override public void forEachRemaining(Consumer<? super K> action) { requireNonNull(action); Consumer<Node<K, V>> consumer = node -> { K key = node.getKey(); V value = node.getValue(); long now = cache.expirationTicker().read(); if ((key != null) && (value != null) && node.isAlive() && !cache.hasExpired(node, now)) { action.accept(key); } }; spliterator.forEachRemaining(consumer); }
@Override public void forEachRemaining(Consumer<? super V> action) { requireNonNull(action); Consumer<Node<K, V>> consumer = node -> { K key = node.getKey(); V value = node.getValue(); long now = cache.expirationTicker().read(); if ((key != null) && (value != null) && node.isAlive() && !cache.hasExpired(node, now)) { action.accept(value); } }; spliterator.forEachRemaining(consumer); }
@Override public void forEachRemaining(Consumer<? super Entry<K, V>> action) { requireNonNull(action); Consumer<Node<K, V>> consumer = node -> { K key = node.getKey(); V value = node.getValue(); long now = cache.expirationTicker().read(); if ((key != null) && (value != null) && node.isAlive() && !cache.hasExpired(node, now)) { action.accept(new WriteThroughEntry<>(cache, key, value)); } }; spliterator.forEachRemaining(consumer); }
@Override public @Nullable V getIfPresentQuietly(Object key, long[/* 1 */] writeTime) { V value; Node<K, V> node = data.get(nodeFactory.newLookupKey(key)); if ((node == null) || ((value = node.getValue()) == null) || hasExpired(node, expirationTicker().read())) { return null; } writeTime[0] = node.getWriteTime(); return value; }
V value = transformer.apply(node.getValue()); if ((key != null) && (value != null) && node.isAlive()) { map.put(key, value);
@Override public final String toString() { return String.format("%s=[key=%s, value=%s, weight=%d, queueType=%,d, accessTimeNS=%,d, " + "writeTimeNS=%,d, varTimeNs=%,d, prevInAccess=%s, nextInAccess=%s, prevInWrite=%s, " + "nextInWrite=%s]", getClass().getSimpleName(), getKey(), getValue(), getWeight(), getQueueType(), getAccessTime(), getWriteTime(), getVariableTime(), getPreviousInAccessOrder() != null, getNextInAccessOrder() != null, getPreviousInWriteOrder() != null, getNextInWriteOrder() != null); } }
@Override public boolean tryAdvance(Consumer<? super V> action) { requireNonNull(action); boolean[] advanced = { false }; long now = cache.expirationTicker().read(); Consumer<Node<K, V>> consumer = node -> { K key = node.getKey(); V value = node.getValue(); if ((key != null) && (value != null) && !cache.hasExpired(node, now) && node.isAlive()) { action.accept(value); advanced[0] = true; } }; for (;;) { if (spliterator.tryAdvance(consumer)) { if (advanced[0]) { return true; } continue; } return false; } }
@Override public boolean tryAdvance(Consumer<? super K> action) { requireNonNull(action); boolean[] advanced = { false }; Consumer<Node<K, V>> consumer = node -> { K key = node.getKey(); V value = node.getValue(); long now = cache.expirationTicker().read(); if ((key != null) && (value != null) && node.isAlive() && !cache.hasExpired(node, now)) { action.accept(key); advanced[0] = true; } }; for (;;) { if (spliterator.tryAdvance(consumer)) { if (advanced[0]) { return true; } continue; } return false; } }
@Override public @Nullable V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { requireNonNull(key); requireNonNull(remappingFunction); // A optimistic fast path to avoid unnecessary locking Object lookupKey = nodeFactory.newLookupKey(key); @Nullable Node<K, V> node = data.get(lookupKey); long now; if (node == null) { return null; } else if ((node.getValue() == null) || hasExpired(node, (now = expirationTicker().read()))) { scheduleDrainBuffers(); return null; } BiFunction<? super K, ? super V, ? extends V> statsAwareRemappingFunction = statsAware(remappingFunction, /* recordMiss */ false, /* recordLoad */ true); return remap(key, lookupKey, statsAwareRemappingFunction, new long[] { now }, /* computeIfAbsent */ false); }
@Override public boolean tryAdvance(Consumer<? super Entry<K, V>> action) { requireNonNull(action); boolean[] advanced = { false }; Consumer<Node<K, V>> consumer = node -> { K key = node.getKey(); V value = node.getValue(); long now = cache.expirationTicker().read(); if ((key != null) && (value != null) && node.isAlive() && !cache.hasExpired(node, now)) { action.accept(new WriteThroughEntry<>(cache, key, value)); advanced[0] = true; } }; for (;;) { if (spliterator.tryAdvance(consumer)) { if (advanced[0]) { return true; } continue; } return false; } }
V value; Node<K, V> node = data.get(nodeFactory.newLookupKey(key)); if ((node == null) || ((value = node.getValue()) == null) || hasExpired(node, now)) { misses++; } else {
@Override public @Nullable V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction, boolean recordStats, boolean recordLoad) { requireNonNull(key); requireNonNull(mappingFunction); long now = expirationTicker().read(); // An optimistic fast path to avoid unnecessary locking Node<K, V> node = data.get(nodeFactory.newLookupKey(key)); if (node != null) { V value = node.getValue(); if ((value != null) && !hasExpired(node, now)) { if (!isComputingAsync(node)) { setVariableTime(node, expireAfterRead(node, key, value, expiry(), now)); setAccessTime(node, now); } afterRead(node, now, /* recordHit */ true); return value; } } if (recordStats) { mappingFunction = statsAware(mappingFunction, recordLoad); } Object keyRef = nodeFactory.newReferenceKey(key, keyReferenceQueue()); return doComputeIfAbsent(key, keyRef, mappingFunction, new long[] { now }); }
@Test(dataProvider = "caches") @CacheSpec(compute = Compute.SYNC, implementation = Implementation.Caffeine, population = Population.FULL, maximumSize = Maximum.FULL) public void updateRecency_onReplaceConditionally( Cache<Integer, Integer> cache, CacheContext context) { BoundedLocalCache<Integer, Integer> localCache = asBoundedLocalCache(cache); Node<Integer, Integer> first = firstBeforeAccess(localCache, context); Integer value = first.getValue(); updateRecency(localCache, context, () -> localCache.replace(first.getKey(), value, value)); }
oldValue = node.getValue(); if (node.isAlive()) { node.retire();
@Override public @Nullable V getIfPresent(Object key, boolean recordStats) { Node<K, V> node = data.get(nodeFactory.newLookupKey(key)); if (node == null) { if (recordStats) { statsCounter().recordMisses(1); } return null; } V value = node.getValue(); long now = expirationTicker().read(); if (hasExpired(node, now) || (collectValues() && (value == null))) { if (recordStats) { statsCounter().recordMisses(1); } scheduleDrainBuffers(); return null; } if (!isComputingAsync(node)) { @SuppressWarnings("unchecked") K castedKey = (K) key; setAccessTime(node, now); setVariableTime(node, expireAfterRead(node, castedKey, value, expiry(), now)); } afterRead(node, now, recordStats); return value; }