Skip to content

Commit 395e91c

Browse files
committed
Reduce cache density
1 parent 1ceddb5 commit 395e91c

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

snap-common/src/main/java/org/snapscript/common/CopyOnWriteCache.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ public class CopyOnWriteCache<K, V> implements Cache<K, V> {
1010
private volatile Map<K, V> cache;
1111

1212
public CopyOnWriteCache() {
13+
this(16);
14+
}
15+
16+
public CopyOnWriteCache(int size) {
17+
this(16, 0.5f);
18+
}
19+
20+
public CopyOnWriteCache(int size, float density) {
21+
this.updater = new MapUpdater(size, density);
1322
this.cache = new HashMap<K, V>();
14-
this.updater = new MapUpdater();
1523
}
1624

1725
@Override
@@ -57,17 +65,22 @@ public int size() {
5765
private class MapUpdater {
5866

5967
private final Map<K, V> empty;
68+
private final float density;
69+
private final int size;
6070

61-
public MapUpdater() {
71+
public MapUpdater(int size, float density) {
6272
this.empty = new HashMap<K, V>();
73+
this.density = density;
74+
this.size = size;
6375
}
6476

6577
public synchronized void cache(K key, V value) {
6678
V existing = cache.get(key);
6779

6880
if(existing != value) { // reduce churn
69-
Map<K, V> copy = new HashMap<K, V>(cache);
81+
Map<K, V> copy = new HashMap<K, V>(size, density);
7082

83+
copy.putAll(cache);
7184
copy.put(key, value);
7285
cache = copy;
7386
}
@@ -77,8 +90,9 @@ public synchronized V take(K key) {
7790
V existing = cache.get(key);
7891

7992
if(existing != null) {
80-
Map<K, V> copy = new HashMap<K, V>(cache);
81-
93+
Map<K, V> copy = new HashMap<K, V>(size, density);
94+
95+
copy.putAll(cache);
8296
copy.remove(key);
8397
cache = copy;
8498
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.snapscript.core;
2+
3+
import java.security.SecureRandom;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
import java.util.Random;
7+
8+
import junit.framework.TestCase;
9+
10+
public class HashMapLoadFactorTest extends TestCase {
11+
12+
private static final int ITERATIONS = 10;
13+
private static final int CAPACITY = 1000000;
14+
15+
public void testLoadFactor() throws Exception{
16+
Random random = new SecureRandom();
17+
String[] keys = new String[CAPACITY];
18+
19+
for(int i = 0; i< keys.length; i++){
20+
keys[i] = "key-" + random.nextInt(CAPACITY);
21+
}
22+
for(int i = 0; i < ITERATIONS; i++) {
23+
measurePerformance(keys, 0.75f);
24+
measurePerformance(keys, 0.50f);
25+
measurePerformance(keys, 0.35f);
26+
}
27+
}
28+
29+
private void measurePerformance(String[] keys, float loadFactor) {
30+
Map<String, String> map = new HashMap<String, String>(keys.length, loadFactor);
31+
for(int i = 0; i< keys.length; i++){
32+
map.put(keys[i], keys[i]);
33+
}
34+
long start = System.currentTimeMillis();
35+
for(int i = 0; i< keys.length; i++){
36+
map.get(i);
37+
}
38+
long finish = System.currentTimeMillis();
39+
System.err.println("loadFactor="+loadFactor+" time="+(finish-start));
40+
}
41+
42+
}

0 commit comments

Comments
 (0)