Reworked cache, this time with less hashmap accesses.

This commit is contained in:
Harrison Deng 2020-04-25 22:32:25 -05:00
parent dcec9fd7e7
commit f20515fd45
3 changed files with 68 additions and 54 deletions

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}