Reworked cache, this time with less hashmap accesses.
This commit is contained in:
parent
dcec9fd7e7
commit
f20515fd45
@ -1,59 +1,38 @@
|
||||
package ca.recrown.islandsurvivalcraft.caching;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class Cache<Key, Value> {
|
||||
private final int maxSize;
|
||||
private final HashMap<Key, Value> data;
|
||||
private final HashMap<Key, Integer> occurrences;
|
||||
private final LinkedList<Key> occurrenceOrder;
|
||||
private final ConcurrentHashMap<Key, CacheValue<Value>> data;
|
||||
private final ConcurrentLinkedQueue<Key> occurrenceOrder;
|
||||
|
||||
public Cache(int maxSize) {
|
||||
data = new HashMap<>(maxSize);
|
||||
occurrenceOrder = new LinkedList<>();
|
||||
data = new ConcurrentHashMap<>(maxSize);
|
||||
occurrenceOrder = new ConcurrentLinkedQueue<>();
|
||||
this.maxSize = maxSize;
|
||||
this.occurrences = new HashMap<>();
|
||||
}
|
||||
|
||||
public Cache() {
|
||||
this(1024);
|
||||
}
|
||||
|
||||
public synchronized void setValue(Key key, Value value) {
|
||||
if (!data.containsKey(key)) {
|
||||
if (data.size() >= maxSize) {
|
||||
while (occurrences.get(occurrenceOrder.peek()) > 1) {
|
||||
occurencesTrackedPoll();
|
||||
}
|
||||
data.remove(occurencesTrackedPoll());
|
||||
}
|
||||
occurrencesTrackedAdd(key);
|
||||
}
|
||||
data.put(key, value);
|
||||
}
|
||||
|
||||
|
||||
private void occurrencesTrackedAdd(Key key) {
|
||||
int occ = 0;
|
||||
if (occurrences.get(key) != null) {
|
||||
occ = occurrences.get(key);
|
||||
}
|
||||
occ++;
|
||||
occurrences.put(key, occ);
|
||||
public void setValue(Key key, Value value) {
|
||||
data.put(key, new CacheValue<>(value));
|
||||
occurrenceOrder.add(key);
|
||||
}
|
||||
|
||||
private Key occurencesTrackedPoll() {
|
||||
Key key = occurrenceOrder.poll();
|
||||
int occ = 0;
|
||||
if (occurrences.get(key) != null) {
|
||||
occ = occurrences.get(key);
|
||||
if (data.size() > maxSize) {
|
||||
int occ = 0;
|
||||
do {
|
||||
Key potentialKey = occurrenceOrder.poll();
|
||||
CacheValue<Value> potential = data.get(potentialKey);
|
||||
potential.decreaseOccurence();
|
||||
occ = potential.getOccurrence();
|
||||
if (occ < 1) {
|
||||
data.remove(potentialKey);
|
||||
}
|
||||
} while (occ > 0);
|
||||
}
|
||||
occ--;
|
||||
if (occ < 0) throw new IllegalStateException();
|
||||
occurrences.put(key, occ);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,14 +42,17 @@ public class Cache<Key, Value> {
|
||||
* @param key the key associated with the value.
|
||||
* @return the value associated to the key.
|
||||
*/
|
||||
public synchronized Value getValue(Key key) {
|
||||
occurrencesTrackedAdd(key);
|
||||
return data.get(key);
|
||||
public Value getValue(Key key) {
|
||||
CacheValue<Value> res = data.get(key);
|
||||
if (res == null) return null;
|
||||
|
||||
res.increaseOccurrence();
|
||||
occurrenceOrder.add(key);
|
||||
return res.getValue();
|
||||
}
|
||||
|
||||
public synchronized void clearCache() {
|
||||
public void clearCache() {
|
||||
data.clear();
|
||||
occurrenceOrder.clear();
|
||||
occurrences.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package ca.recrown.islandsurvivalcraft.caching;
|
||||
|
||||
public class CacheValue <ValueType> {
|
||||
private int occurrence = 1;
|
||||
private final ValueType value;
|
||||
|
||||
/**
|
||||
* @return the occurrence
|
||||
*/
|
||||
public int getOccurrence() {
|
||||
return occurrence;
|
||||
}
|
||||
|
||||
public void increaseOccurrence() {
|
||||
occurrence++;
|
||||
}
|
||||
|
||||
public void decreaseOccurence() {
|
||||
occurrence--;
|
||||
}
|
||||
|
||||
public CacheValue(ValueType value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
public ValueType getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -66,10 +66,10 @@ public class CacheTest {
|
||||
|
||||
Cache<Integer, Integer> largeCache = new Cache<>(amount/2);
|
||||
|
||||
int[] expected = new int[amount];
|
||||
int[] values = new int[amount];
|
||||
for (int i = 0; i < amount; i++) {
|
||||
expected[i] = random.nextInt();
|
||||
largeCache.setValue(i, expected[i]);
|
||||
values[i] = random.nextInt();
|
||||
largeCache.setValue(i, values[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < amount /2; i++) {
|
||||
@ -77,7 +77,7 @@ public class CacheTest {
|
||||
}
|
||||
|
||||
for (int i = amount /2; i < amount; i++) {
|
||||
assertEquals(expected[i], largeCache.getValue(i), "Current accessor: " + i);
|
||||
assertEquals(values[i], largeCache.getValue(i), "Current accessor: " + i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,10 +88,10 @@ public class CacheTest {
|
||||
|
||||
Cache<Integer, Integer> largeCache = new Cache<>(amount/2);
|
||||
|
||||
int[] expected = new int[amount];
|
||||
int[] values = new int[amount];
|
||||
for (int i = 0; i < amount; i++) {
|
||||
expected[i] = random.nextInt();
|
||||
largeCache.setValue(i, expected[i]);
|
||||
values[i] = random.nextInt();
|
||||
largeCache.setValue(i, values[i]);
|
||||
largeCache.getValue(0);
|
||||
}
|
||||
|
||||
@ -100,9 +100,9 @@ public class CacheTest {
|
||||
}
|
||||
|
||||
for (int i = (amount /2) + 1; i < amount; i++) {
|
||||
assertEquals(expected[i], largeCache.getValue(i), "Current accessor: " + i);
|
||||
assertEquals(values[i], largeCache.getValue(i), "Current accessor: " + i);
|
||||
}
|
||||
|
||||
assertEquals(expected[0], largeCache.getValue(0));
|
||||
assertEquals(values[0], largeCache.getValue(0));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user