/** Drains the weak key references queue. */ @GuardedBy("evictionLock") void drainKeyReferences() { if (!collectKeys()) { return; } Reference<? extends K> keyRef; while ((keyRef = keyReferenceQueue().poll()) != null) { Node<K, V> node = data.get(keyRef); if (node != null) { evictEntry(node, RemovalCause.COLLECTED, 0L); } } }
/** Drains the weak / soft value references queue. */ @GuardedBy("evictionLock") void drainValueReferences() { if (!collectValues()) { return; } Reference<? extends V> valueRef; while ((valueRef = valueReferenceQueue().poll()) != null) { @SuppressWarnings("unchecked") InternalReference<V> ref = (InternalReference<V>) valueRef; Node<K, V> node = data.get(ref.getKeyReference()); if ((node != null) && (valueRef == node.getValueReference())) { evictEntry(node, RemovalCause.COLLECTED, 0L); } } }
/** Expires entries in an access-order queue. */ @GuardedBy("evictionLock") void expireAfterAccessEntries(AccessOrderDeque<Node<K, V>> accessOrderDeque, long now) { long duration = expiresAfterAccessNanos(); for (;;) { Node<K, V> node = accessOrderDeque.peekFirst(); if ((node == null) || ((now - node.getAccessTime()) < duration)) { return; } evictEntry(node, RemovalCause.EXPIRED, now); } }
@Test(dataProvider = "schedule") public void schedule(long nanos, int expired) { when(cache.evictEntry(captor.capture(), any(), anyLong())).thenReturn(true); for (int timeout : new int[] { 25, 90, 240 }) { timerWheel.schedule(new Timer(TimeUnit.SECONDS.toNanos(timeout))); } timerWheel.advance(nanos); verify(cache, times(expired)).evictEntry(any(), any(), anyLong()); for (Node<?, ?> node : captor.getAllValues()) { assertThat(node.getVariableTime(), is(lessThan(nanos))); } }
@Test public void expire_reschedule() { when(cache.evictEntry(captor.capture(), any(), anyLong())).thenAnswer(invocation -> { Timer timer = (Timer) invocation.getArgument(0); timer.setVariableTime(timerWheel.nanos + 100); return false; }); timerWheel.schedule(new Timer(100)); timerWheel.advance(TimerWheel.SPANS[0]); verify(cache).evictEntry(any(), any(), anyLong()); assertThat(captor.getValue().getNextInVariableOrder(), is(not(nullValue()))); assertThat(captor.getValue().getPreviousInVariableOrder(), is(not(nullValue()))); }
@Test public void reschedule() { when(cache.evictEntry(captor.capture(), any(), anyLong())).thenReturn(true); Timer timer = new Timer(TimeUnit.MINUTES.toNanos(15)); timerWheel.schedule(timer); Node<?, ?> startBucket = timer.getNextInVariableOrder(); timer.setVariableTime(TimeUnit.HOURS.toNanos(2)); timerWheel.reschedule(timer); assertThat(timer.getNextInVariableOrder(), is(not(startBucket))); timerWheel.advance(TimeUnit.DAYS.toNanos(1)); checkEmpty(); }
@Test(dataProvider = "fuzzySchedule") public void schedule_fuzzy(long clock, long nanos, long[] times) { when(cache.evictEntry(captor.capture(), any(), anyLong())).thenReturn(true); timerWheel.nanos = clock; int expired = 0; for (long timeout : times) { if (timeout <= nanos) { expired++; } timerWheel.schedule(new Timer(timeout)); } timerWheel.advance(nanos); verify(cache, times(expired)).evictEntry(any(), any(), anyLong()); for (Node<?, ?> node : captor.getAllValues()) { assertThat(node.getVariableTime(), is(lessThan(nanos))); } checkTimerWheel(nanos); }
/** Expires entries on the write-order queue. */ @GuardedBy("evictionLock") void expireAfterWriteEntries(long now) { if (!expiresAfterWrite()) { return; } long duration = expiresAfterWriteNanos(); for (;;) { final Node<K, V> node = writeOrderDeque().peekFirst(); if ((node == null) || ((now - node.getWriteTime()) < duration)) { break; } evictEntry(node, RemovalCause.EXPIRED, now); } }
candidate = previous; candidates--; evictEntry(evict, RemovalCause.SIZE, 0L); continue; } else if (candidate == null) { Node<K, V> evict = victim; victim = victim.getNextInAccessOrder(); evictEntry(evict, RemovalCause.SIZE, 0L); continue; @NonNull Node<K, V> evict = victim; victim = victim.getNextInAccessOrder(); evictEntry(evict, RemovalCause.COLLECTED, 0L); continue; } else if (candidateKey == null) { @NonNull Node<K, V> evict = candidate; candidate = candidate.getPreviousInAccessOrder(); evictEntry(evict, RemovalCause.COLLECTED, 0L); continue; Node<K, V> evict = candidate; candidate = candidate.getPreviousInAccessOrder(); evictEntry(evict, RemovalCause.SIZE, 0L); continue; Node<K, V> evict = victim; victim = victim.getNextInAccessOrder(); evictEntry(evict, RemovalCause.SIZE, 0L);
localCache.evictEntry(node, RemovalCause.SIZE, 0L);
|| !cache.evictEntry(node, RemovalCause.EXPIRED, nanos)) { Node<K, V> newSentinel = findBucket(node.getVariableTime()); link(newSentinel, node);
/** Drains the weak key references queue. */ @GuardedBy("evictionLock") void drainKeyReferences() { if (!collectKeys()) { return; } Reference<? extends K> keyRef; while ((keyRef = keyReferenceQueue().poll()) != null) { Node<K, V> node = data.get(keyRef); if (node != null) { evictEntry(node, RemovalCause.COLLECTED, 0L); } } }
/** Expires entries in an access-order queue. */ @GuardedBy("evictionLock") void expireAfterAccessEntries(AccessOrderDeque<Node<K, V>> accessOrderDeque, long now) { long duration = expiresAfterAccessNanos(); for (;;) { Node<K, V> node = accessOrderDeque.peekFirst(); if ((node == null) || ((now - node.getAccessTime()) < duration)) { return; } evictEntry(node, RemovalCause.EXPIRED, now); } }
/** Drains the weak / soft value references queue. */ @GuardedBy("evictionLock") void drainValueReferences() { if (!collectValues()) { return; } Reference<? extends V> valueRef; while ((valueRef = valueReferenceQueue().poll()) != null) { @SuppressWarnings("unchecked") InternalReference<V> ref = (InternalReference<V>) valueRef; Node<K, V> node = data.get(ref.getKeyReference()); if ((node != null) && (valueRef == node.getValueReference())) { evictEntry(node, RemovalCause.COLLECTED, 0L); } } }
/** Expires entries on the write-order queue. */ @GuardedBy("evictionLock") void expireAfterWriteEntries(long now) { if (!expiresAfterWrite()) { return; } long duration = expiresAfterWriteNanos(); for (;;) { final Node<K, V> node = writeOrderDeque().peekFirst(); if ((node == null) || ((now - node.getWriteTime()) < duration)) { break; } evictEntry(node, RemovalCause.EXPIRED, now); } }
candidate = previous; candidates--; evictEntry(evict, RemovalCause.SIZE, 0L); continue; } else if (candidate == null) { Node<K, V> evict = victim; victim = victim.getNextInAccessOrder(); evictEntry(evict, RemovalCause.SIZE, 0L); continue; @Nonnull Node<K, V> evict = victim; victim = victim.getNextInAccessOrder(); evictEntry(evict, RemovalCause.COLLECTED, 0L); continue; } else if (candidateKey == null) { @Nonnull Node<K, V> evict = candidate; candidate = candidate.getPreviousInAccessOrder(); evictEntry(evict, RemovalCause.COLLECTED, 0L); continue; Node<K, V> evict = candidate; candidate = candidate.getPreviousInAccessOrder(); evictEntry(evict, RemovalCause.SIZE, 0L); continue; Node<K, V> evict = victim; victim = victim.getNextInAccessOrder(); evictEntry(evict, RemovalCause.SIZE, 0L);
|| !cache.evictEntry(node, RemovalCause.EXPIRED, nanos)) { Node<K, V> newSentinel = findBucket(node.getVariableTime()); link(newSentinel, node);