void setVariableTime(Node<K, V> node, long expirationTime) { if (expiresVariable()) { node.setVariableTime(expirationTime); } }
@Override public Optional<VarExpiration<K, V>> expireVariably() { if (!cache.expiresVariable()) { return Optional.empty(); } return (variable == null) ? (variable = Optional.of(new BoundedVarExpiration())) : variable; } @Override public Optional<Expiration<K, V>> refreshAfterWrite() {
/** * Returns the expiration time for the entry after being created. * * @param key the key of the entry that was created * @param value the value of the entry that was created * @param expiry the calculator for the expiration time * @param now the current time, in nanoseconds * @return the expiration time */ long expireAfterCreate(@Nullable K key, @Nullable V value, Expiry<K, V> expiry, long now) { if (expiresVariable() && (key != null) && (value != null)) { long duration = expiry.expireAfterCreate(key, value, now); return isAsync ? (now + duration) : (now + Math.min(duration, MAXIMUM_EXPIRY)); } return 0L; }
/** Expires entries in the timer wheel. */ @GuardedBy("evictionLock") void expireVariableEntries(long now) { if (expiresVariable()) { timerWheel().advance(now); } }
/** * Returns the access time for the entry after a read. * * @param node the entry in the page replacement policy * @param key the key of the entry that was read * @param value the value of the entry that was read * @param expiry the calculator for the expiration time * @param now the current time, in nanoseconds * @return the expiration time */ long expireAfterRead(Node<K, V> node, @Nullable K key, @Nullable V value, Expiry<K, V> expiry, long now) { if (expiresVariable() && (key != null) && (value != null)) { long currentDuration = Math.max(1, node.getVariableTime() - now); long duration = expiry.expireAfterRead(key, value, now, currentDuration); return isAsync ? (now + duration) : (now + Math.min(duration, MAXIMUM_EXPIRY)); } return 0L; }
/** * Returns the expiration time for the entry after being updated. * * @param node the entry in the page replacement policy * @param key the key of the entry that was updated * @param value the value of the entry that was updated * @param expiry the calculator for the expiration time * @param now the current time, in nanoseconds * @return the expiration time */ long expireAfterUpdate(Node<K, V> node, @Nullable K key, @Nullable V value, Expiry<K, V> expiry, long now) { if (expiresVariable() && (key != null) && (value != null)) { long currentDuration = Math.max(1, node.getVariableTime() - now); long duration = expiry.expireAfterUpdate(key, value, now, currentDuration); return isAsync ? (now + duration) : (now + Math.min(duration, MAXIMUM_EXPIRY)); } return 0L; }
/** Returns if the entry has expired. */ @SuppressWarnings("ShortCircuitBoolean") boolean hasExpired(Node<K, V> node, long now) { return (expiresAfterAccess() && (now - node.getAccessTime() >= expiresAfterAccessNanos())) | (expiresAfterWrite() && (now - node.getWriteTime() >= expiresAfterWriteNanos())) | (expiresVariable() && (now - node.getVariableTime() >= 0)); }
if (original.expiresVariable()) { desc.expectThat("same expiry", unwrapExpiry(copy.expiry()).getClass(), is(equalTo(unwrapExpiry(original.expiry()).getClass()))); } else { desc.expectThat("", copy.expiresVariable(), is(false));
/** Creates a serialization proxy based on the common configuration shared by all cache types. */ static <K, V> SerializationProxy<K, V> makeSerializationProxy( BoundedLocalCache<?, ?> cache, boolean isWeighted) { SerializationProxy<K, V> proxy = new SerializationProxy<>(); proxy.weakKeys = cache.collectKeys(); proxy.weakValues = cache.nodeFactory.weakValues(); proxy.softValues = cache.nodeFactory.softValues(); proxy.isRecordingStats = cache.isRecordingStats(); proxy.removalListener = cache.removalListener(); proxy.ticker = cache.expirationTicker(); proxy.writer = cache.writer; if (cache.expiresAfterAccess()) { proxy.expiresAfterAccessNanos = cache.expiresAfterAccessNanos(); } if (cache.expiresAfterWrite()) { proxy.expiresAfterWriteNanos = cache.expiresAfterWriteNanos(); } if (cache.expiresVariable()) { proxy.expiry = cache.expiry(); } if (cache.evicts()) { if (isWeighted) { proxy.weigher = cache.weigher; proxy.maximumWeight = cache.maximum(); } else { proxy.maximumSize = cache.maximum(); } } return proxy; }
private void checkTimerWheel(BoundedLocalCache<K, V> cache) { if (!cache.expiresVariable()) { return; } Set<Node<K, V>> seen = Sets.newIdentityHashSet(); for (int i = 0; i < cache.timerWheel().wheel.length; i++) { for (int j = 0; j < cache.timerWheel().wheel[i].length; j++) { Node<K, V> sentinel = cache.timerWheel().wheel[i][j]; desc.expectThat("Wrong sentinel prev", sentinel.getPreviousInVariableOrder().getNextInVariableOrder(), sameInstance(sentinel)); desc.expectThat("Wrong sentinel next", sentinel.getNextInVariableOrder().getPreviousInVariableOrder(), sameInstance(sentinel)); desc.expectThat("Sentinel must be first element", sentinel, instanceOf(Sentinel.class)); for (Node<K, V> node = sentinel.getNextInVariableOrder(); node != sentinel; node = node.getNextInVariableOrder()) { Node<K, V> next = node.getNextInVariableOrder(); Node<K, V> prev = node.getPreviousInVariableOrder(); long duration = node.getVariableTime() - cache.timerWheel().nanos; desc.expectThat("Expired", duration, greaterThan(0L)); desc.expectThat("Loop detected", seen.add(node), is(true)); desc.expectThat("Wrong prev", prev.getNextInVariableOrder(), is(sameInstance(node))); desc.expectThat("Wrong next", next.getPreviousInVariableOrder(), is(sameInstance(node))); } } } desc.expectThat("Timers != Entries", seen, hasSize(cache.size())); }
/** Updates the node's location in the page replacement policy. */ @GuardedBy("evictionLock") void onAccess(Node<K, V> node) { if (evicts()) { K key = node.getKey(); if (key == null) { return; } frequencySketch().increment(key); if (node.inEden()) { reorder(accessOrderEdenDeque(), node); } else if (node.inMainProbation()) { reorderProbation(node); } else { reorder(accessOrderProtectedDeque(), node); } } else if (expiresAfterAccess()) { reorder(accessOrderEdenDeque(), node); } if (expiresVariable()) { timerWheel().reschedule(node); } }
void setVariableTime(Node<K, V> node, long expirationTime) { if (expiresVariable()) { node.setVariableTime(expirationTime); } }
@Override public Optional<VarExpiration<K, V>> expireVariably() { if (!cache.expiresVariable()) { return Optional.empty(); } return (variable == null) ? (variable = Optional.of(new BoundedVarExpiration())) : variable; } @Override public Optional<Expiration<K, V>> refreshAfterWrite() {
/** * Returns the expiration time for the entry after being created. * * @param key the key of the entry that was created * @param value the value of the entry that was created * @param expiry the calculator for the expiration time * @param now the current time, in nanoseconds * @return the expiration time */ long expireAfterCreate(@Nullable K key, @Nullable V value, Expiry<K, V> expiry, long now) { if (expiresVariable() && (key != null) && (value != null)) { long duration = expiry.expireAfterCreate(key, value, now); return isAsync ? (now + duration) : (now + Math.min(duration, MAXIMUM_EXPIRY)); } return 0L; }
/** Expires entries in the timer wheel. */ @GuardedBy("evictionLock") void expireVariableEntries(long now) { if (expiresVariable()) { timerWheel().advance(now); } }
/** * Returns the expiration time for the entry after being updated. * * @param node the entry in the page replacement policy * @param key the key of the entry that was updated * @param value the value of the entry that was updated * @param expiry the calculator for the expiration time * @param now the current time, in nanoseconds * @return the expiration time */ long expireAfterUpdate(Node<K, V> node, @Nullable K key, @Nullable V value, Expiry<K, V> expiry, long now) { if (expiresVariable() && (key != null) && (value != null)) { long currentDuration = Math.max(1, node.getVariableTime() - now); long duration = expiry.expireAfterUpdate(key, value, now, currentDuration); return isAsync ? (now + duration) : (now + Math.min(duration, MAXIMUM_EXPIRY)); } return 0L; }
expired |= ((now - n.getWriteTime()) >= expiresAfterWriteNanos()); if (expiresVariable()) { expired |= (n.getVariableTime() <= now); } else if (expiresVariable()) { timerWheel().deschedule(node);
/** * Returns the access time for the entry after a read. * * @param node the entry in the page replacement policy * @param key the key of the entry that was read * @param value the value of the entry that was read * @param expiry the calculator for the expiration time * @param now the current time, in nanoseconds * @return the expiration time */ long expireAfterRead(Node<K, V> node, @Nullable K key, @Nullable V value, Expiry<K, V> expiry, long now) { if (expiresVariable() && (key != null) && (value != null)) { long currentDuration = Math.max(1, node.getVariableTime() - now); long duration = expiry.expireAfterRead(key, value, now, currentDuration); return isAsync ? (now + duration) : (now + Math.min(duration, MAXIMUM_EXPIRY)); } return 0L; }
} else if (expiresVariable()) { timerWheel().deschedule(node);
/** Returns if the entry has expired. */ @SuppressWarnings("ShortCircuitBoolean") boolean hasExpired(Node<K, V> node, long now) { return (expiresAfterAccess() && (now - node.getAccessTime() >= expiresAfterAccessNanos())) | (expiresAfterWrite() && (now - node.getWriteTime() >= expiresAfterWriteNanos())) | (expiresVariable() && (now - node.getVariableTime() >= 0)); }