only iterates over elements when at least one element can be evicted

This commit is contained in:
2018-11-23 06:34:41 +01:00
parent f78f69328b
commit 64771417e4

View File

@@ -98,8 +98,8 @@ public class HotEntryCache<K, V> {
return value; return value;
} }
public void touch(final Clock clock) { public void touch(final Instant instant) {
lastAccessed = Instant.now(clock); lastAccessed = instant;
} }
} }
@@ -114,6 +114,8 @@ public class HotEntryCache<K, V> {
private Clock clock; private Clock clock;
private Instant nextEviction = Instant.MAX;
HotEntryCache(final Duration timeToLive, final Clock clock, final long delayForEvictionThread, HotEntryCache(final Duration timeToLive, final Clock clock, final long delayForEvictionThread,
final TimeUnit timeUnit) { final TimeUnit timeUnit) {
this.timeToLive = timeToLive; this.timeToLive = timeToLive;
@@ -131,12 +133,13 @@ public class HotEntryCache<K, V> {
public V get(final K key) { public V get(final K key) {
final Entry<V> entry = cache.computeIfPresent(key, (k, e) -> { final Entry<V> entry = cache.computeIfPresent(key, (k, e) -> {
if (isExpired(e)) { final Instant now = Instant.now(clock);
if (isExpired(e, now)) {
handleEvent(EventType.EVICTED, k, e.getValue()); handleEvent(EventType.EVICTED, k, e.getValue());
return null; return null;
} }
e.touch(clock); touch(e);
return e; return e;
}); });
return entry != null ? entry.getValue() : null; return entry != null ? entry.getValue() : null;
@@ -147,7 +150,9 @@ public class HotEntryCache<K, V> {
final AtomicReference<Entry<V>> oldValue = new AtomicReference<>(); final AtomicReference<Entry<V>> oldValue = new AtomicReference<>();
cache.compute(key, (k, v) -> { cache.compute(key, (k, v) -> {
oldValue.set(v); oldValue.set(v);
return new Entry<>(value, clock); final Entry<V> newEntry = new Entry<>(value, clock);
touch(newEntry);
return newEntry;
}); });
return oldValue.get() != null ? oldValue.get().getValue() : null; return oldValue.get() != null ? oldValue.get().getValue() : null;
} }
@@ -172,9 +177,8 @@ public class HotEntryCache<K, V> {
return new Entry<>(value, clock); return new Entry<>(value, clock);
}); });
if (entry != null) { touch(entry);
entry.touch(clock);
}
return entry != null ? entry.getValue() : null; return entry != null ? entry.getValue() : null;
} }
@@ -197,26 +201,37 @@ public class HotEntryCache<K, V> {
public void forEach(final Consumer<V> consumer) { public void forEach(final Consumer<V> consumer) {
cache.forEachValue(Long.MAX_VALUE, entry -> { cache.forEachValue(Long.MAX_VALUE, entry -> {
entry.touch(clock); touch(entry);
consumer.accept(entry.getValue()); consumer.accept(entry.getValue());
}); });
} }
private void evict() { private void evict() {
for (final K key : cache.keySet()) { final Instant now = Instant.now(clock);
if (nextEviction.isBefore(now)) {
cache.computeIfPresent(key, (k, e) -> { for (final K key : cache.keySet()) {
if (isExpired(e)) { cache.computeIfPresent(key, (k, e) -> {
handleEvent(EventType.EVICTED, k, e.getValue()); if (isExpired(e, now)) {
return null; handleEvent(EventType.EVICTED, k, e.getValue());
} return null;
return e; }
}); return e;
});
}
} }
} }
private boolean isExpired(final Entry<V> entry) { private void touch(final Entry<V> entry) {
return entry.getLastAccessed().plus(timeToLive).isBefore(Instant.now(clock)); if (entry != null) {
final Instant now = Instant.now(clock);
entry.touch(now);
nextEviction = now.plus(timeToLive);
}
}
private boolean isExpired(final Entry<V> entry, final Instant now) {
return entry.getLastAccessed().plus(timeToLive).isBefore(now);
} }
private void handleEvent(final EventType eventType, final K key, final V value) { private void handleEvent(final EventType eventType, final K key, final V value) {
@@ -227,5 +242,4 @@ public class HotEntryCache<K, V> {
} }
} }
} }
} }