Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.function.BiFunction;

/**
Expand Down Expand Up @@ -76,5 +75,5 @@ interface Backend<K, V> {

void updateUsageInBytesIfRequired(long delta);

Map.Entry<K, OnHeapValueHolder<V>> getEvictionCandidate(Random random, int size, final Comparator<? super Store.ValueHolder<V>> prioritizer, final EvictionAdvisor<Object, ? super OnHeapValueHolder<?>> evictionAdvisor);
Map.Entry<K, OnHeapValueHolder<V>> getEvictionCandidate(int size, final Comparator<? super Store.ValueHolder<V>> prioritizer, final EvictionAdvisor<Object, ? super OnHeapValueHolder<?>> evictionAdvisor);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1567,14 +1567,13 @@ protected void enforceCapacity() {
*/
boolean evict(StoreEventSink<K, V> eventSink) {
evictionObserver.begin();
Random random = new Random();

@SuppressWarnings("unchecked")
Map.Entry<K, OnHeapValueHolder<V>> candidate = map.getEvictionCandidate(random, SAMPLE_SIZE, EVICTION_PRIORITIZER, EVICTION_ADVISOR);
Map.Entry<K, OnHeapValueHolder<V>> candidate = map.getEvictionCandidate(SAMPLE_SIZE, EVICTION_PRIORITIZER, EVICTION_ADVISOR);

if (candidate == null) {
// 2nd attempt without any advisor
candidate = map.getEvictionCandidate(random, SAMPLE_SIZE, EVICTION_PRIORITIZER, noAdvice());
candidate = map.getEvictionCandidate(SAMPLE_SIZE, EVICTION_PRIORITIZER, noAdvice());
}

if (candidate == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public boolean remove(K key, OnHeapValueHolder<V> value) {
}

@Override
public Map.Entry<K, OnHeapValueHolder<V>> getEvictionCandidate(Random random, int size, final Comparator<? super Store.ValueHolder<V>> prioritizer, final EvictionAdvisor<Object, ? super OnHeapValueHolder<?>> evictionAdvisor) {
return realMap.getEvictionCandidate(random, size, prioritizer, evictionAdvisor);
public Map.Entry<K, OnHeapValueHolder<V>> getEvictionCandidate(int size, final Comparator<? super Store.ValueHolder<V>> prioritizer, final EvictionAdvisor<Object, ? super OnHeapValueHolder<?>> evictionAdvisor) {
return realMap.getEvictionCandidate(size, prioritizer, evictionAdvisor);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import static org.ehcache.config.Eviction.noAdvice;
import static org.hamcrest.MatcherAssert.assertThat;
Expand Down Expand Up @@ -118,21 +117,21 @@ public int compareTo(BadHashKey o) {
@Test
public void testRandomSampleOnEmptyMap() {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
assertThat(map.getEvictionCandidate(new Random(), 1, null, noAdvice()), nullValue());
assertThat(map.getEvictionCandidate(1, null, noAdvice()), nullValue());
}

@Test
public void testEmptyRandomSample() {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("foo", "bar");
assertThat(map.getEvictionCandidate(new Random(), 0, null, noAdvice()), nullValue());
assertThat(map.getEvictionCandidate(0, null, noAdvice()), nullValue());
}

@Test
public void testOversizedRandomSample() {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("foo", "bar");
Entry<String, String> candidate = map.getEvictionCandidate(new Random(), 2, null, noAdvice());
Entry<String, String> candidate = map.getEvictionCandidate(2, null, noAdvice());
assertThat(candidate.getKey(), is("foo"));
assertThat(candidate.getValue(), is("bar"));
}
Expand All @@ -143,7 +142,7 @@ public void testUndersizedRandomSample() {
for (int i = 0; i < 1000; i++) {
map.put(Integer.toString(i), Integer.toString(i));
}
Entry<String, String> candidate = map.getEvictionCandidate(new Random(), 2, (t, t1) -> 0, noAdvice());
Entry<String, String> candidate = map.getEvictionCandidate(2, (t, t1) -> 0, noAdvice());
assertThat(candidate, notNullValue());
}

Expand All @@ -153,7 +152,7 @@ public void testFullyAdvisedAgainstEvictionRandomSample() {
for (int i = 0; i < 1000; i++) {
map.put(Integer.toString(i), Integer.toString(i));
}
Entry<String, String> candidate = map.getEvictionCandidate(new Random(), 2, null, (key, value) -> true);
Entry<String, String> candidate = map.getEvictionCandidate(2, null, (key, value) -> true);
assertThat(candidate, nullValue());
}

Expand All @@ -163,7 +162,7 @@ public void testSelectivelyAdvisedAgainstEvictionRandomSample() {
for (int i = 0; i < 1000; i++) {
map.put(Integer.toString(i), Integer.toString(i));
}
Entry<String, String> candidate = map.getEvictionCandidate(new Random(), 20, (t, t1) -> 0, (key, value) -> key.length() > 1);
Entry<String, String> candidate = map.getEvictionCandidate(20, (t, t1) -> 0, (key, value) -> key.length() > 1);
assertThat(candidate.getKey().length(), is(1));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
Expand All @@ -46,6 +47,7 @@
import java.util.Random;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CountedCompleter;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -6478,72 +6480,54 @@ else if (f.hash == MOVED)
return invalidated;
}

public Entry<K, V> getEvictionCandidate(Random rndm, int size, Comparator<? super V> prioritizer, EvictionAdvisor<? super K, ? super V> evictionAdvisor) {
Node<K,V>[] tab = table;
if (tab == null || size == 0) {
return null;
}
private final Deque<Traverser<K, V>> evictionTraversers = new ConcurrentLinkedDeque<>();

K maxKey = null;
V maxValue = null;
public Entry<K, V> getEvictionCandidate(int size, Comparator<? super V> prioritizer, EvictionAdvisor<? super K, ? super V> evictionAdvisor) {
if (size == 0) {
return null;
}

int n = tab.length;
int start = rndm.nextInt(n);
K maxKey = null;
V maxValue = null;

Traverser<K, V> t = new Traverser<>(tab, n, start, n);
for (Node<K, V> p; (p = t.advance()) != null;) {
K key = p.key;
V val = p.val;
if (!evictionAdvisor.adviseAgainstEviction(key, val)) {
if (maxKey == null || prioritizer.compare(val, maxValue) > 0) {
maxKey = key;
maxValue = val;
}
if (--size == 0) {
for (int terminalIndex = t.index; (p = t.advance()) != null && t.index == terminalIndex; ) {
key = p.key;
val = p.val;
if (!evictionAdvisor.adviseAgainstEviction(key, val) && prioritizer.compare(val, maxValue) > 0) {
maxKey = key;
maxValue = val;
}
}
return new MapEntry<>(maxKey, maxValue, this);
}
}
boolean exhaustive = false;
do {
Traverser<K, V> t = evictionTraversers.poll();
if (t == null) {
Node<K, V>[] tab;
int f = (tab = table) == null ? 0 : tab.length;
t = new Traverser<>(tab, f, 0, f);
exhaustive = true;
}

return getEvictionCandidateWrap(tab, start, size, maxKey, maxValue, prioritizer, evictionAdvisor);
}

private Entry<K, V> getEvictionCandidateWrap(Node<K,V>[] tab, int start, int size, K maxKey, V maxVal, Comparator<? super V> prioritizer, EvictionAdvisor<? super K, ? super V> evictionAdvisor) {
Traverser<K, V> t = new Traverser<>(tab, tab.length, 0, start);
for (Node<K, V> p; (p = t.advance()) != null;) {
boolean exhausted = false;
try {
for (Node<K, V> p; (p = t.advance()) != null; ) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this always skip/advance past the table 0 if 't' happens to be the one that was just instantiated above?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, traverser start "before" the first entry, so successive calls to advance every entry in sequence.

K key = p.key;
V val = p.val;
if (!evictionAdvisor.adviseAgainstEviction(key, val)) {
if (maxKey == null || prioritizer.compare(val, maxVal) > 0) {
maxKey = key;
maxVal = val;
}
if (--size == 0) {
for (int terminalIndex = t.index; (p = t.advance()) != null && t.index == terminalIndex; ) {
key = p.key;
val = p.val;
if (!evictionAdvisor.adviseAgainstEviction(key, val) && prioritizer.compare(val, maxVal) > 0) {
maxKey = key;
maxVal = val;
}
}
return new MapEntry<>(maxKey, maxVal, this);
}
if (maxKey == null || prioritizer.compare(val, maxValue) > 0) {
maxKey = key;
maxValue = val;
}
if (--size == 0) {
return new MapEntry<>(maxKey, maxValue, this);
}
}
}
exhausted = true;
} finally {
if (!exhausted) {
evictionTraversers.push(t);
}
}
if (maxKey == null) {
return null;
} else {
return new MapEntry<>(maxKey, maxVal, this);
}
} while (!exhaustive);

if (maxKey == null) {
return null;
} else {
return new MapEntry<>(maxKey, maxValue, this);
}
}
// END OF EHCACHE SPECIFIC
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ public interface EvictingConcurrentMap<K, V> extends ConcurrentMap<K, V>{
/**
* Return the preferred entry to evict based on a sample of entries taken from the map.
*
* @param rndm Random implementation used to determine the sample randomly
* @param size Number of sampled entries
* @param prioritizer Prioritizer used to determine the best entry to evict in the sample
* @param evictionAdvisor Can veto against the eviction of an entry
* @return Entry to evict or null is none was found
*/
Entry<K, V> getEvictionCandidate(Random rndm, int size, Comparator<? super V> prioritizer, EvictionAdvisor<? super K, ? super V> evictionAdvisor);
Entry<K, V> getEvictionCandidate(int size, Comparator<? super V> prioritizer, EvictionAdvisor<? super K, ? super V> evictionAdvisor);

/**
* Returns the number of mappings. This method should be used
Expand Down
Loading