using WeakValueCache for TracTrac DomainFactory;

let go of objects no longer strongly referenced by dedicated weak value caches

Change-Id: I0b6ac5d198b689d5fc1ce8aa5eeeee3c39bce1cd
This commit is contained in:
Axel Uhl committed 2017-08-03 18:11:31 +02:00
1 parent b26fbdaf0d
commit 576b22915a
3 files changed
+100 -8

No files matched your search

@@ -19,7 +19,6 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -85,6 +84,7 @@ import com.sap.sse.common.impl.AbstractColor;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.util.WeakIdentityHashMap;
import com.sap.sse.util.WeakValueCache;
import com.tractrac.model.lib.api.data.IPosition;
import com.tractrac.model.lib.api.event.CreateModelException;
import com.tractrac.model.lib.api.event.ICompetitor;
@@ -105,17 +105,14 @@ public class DomainFactoryImpl implements DomainFactory {
private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory;
// TODO consider (re-)introducing WeakHashMaps for cache structures, but such that the cache is maintained as long as our domain objects are strongly referenced
private final Map<TracTracControlPoint, com.sap.sailing.domain.base.ControlPoint> controlPointCache =
new HashMap<TracTracControlPoint, com.sap.sailing.domain.base.ControlPoint>();
private final WeakValueCache<TracTracControlPoint, com.sap.sailing.domain.base.ControlPoint> controlPointCache = new WeakValueCache<>(new HashMap<>());
private final Map<com.sap.sse.common.Util.Pair<String, UUID>, DynamicPerson> personCache = new HashMap<>();
/**
* Caches regattas by their name and their boat class's name
*/
private final Map<com.sap.sse.common.Util.Pair<String, String>, com.sap.sailing.domain.base.Regatta> regattaCache =
new HashMap<com.sap.sse.common.Util.Pair<String, String>, com.sap.sailing.domain.base.Regatta>();
private final WeakValueCache<com.sap.sse.common.Util.Pair<String, String>, com.sap.sailing.domain.base.Regatta> regattaCache = new WeakValueCache<>(new HashMap<>());
/**
* A cache based on weak references to the TracTrac race, allowing for quick race lookup as long as the
@@ -128,7 +125,7 @@ public class DomainFactoryImpl implements DomainFactory {
* Maps from the TracTrac race UUIDs to the domain model's {@link RaceDefinition} objects that represent the race
* identified by that UUID
*/
private final ConcurrentMap<UUID, RaceDefinition> raceCache = new ConcurrentHashMap<>();
private final WeakValueCache<UUID, RaceDefinition> raceCache = new WeakValueCache<>(new ConcurrentHashMap<>());
private final MetadataParser metadataParser;
@@ -136,7 +133,7 @@ public class DomainFactoryImpl implements DomainFactory {
this.baseDomainFactory = baseDomainFactory;
this.metadataParser = new MetadataParserImpl();
}
@Override
public MetadataParser getMetadataParser() {
return metadataParser;
@@ -0,0 +1,41 @@
package com.sap.sse.util;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Map;
/**
* A weak reference that, when constructed, enters itself into a given map from where it can be removed
* again using {@link #cleanUp}. The {@link #cleanUp()} method should be called after this weak reference
* has been enqueued into the {@link ReferenceQueue} passed to the constructor.
*
* @author Axel Uhl (D043530)
*
* @param <R>
* the referent's type
* @param <K>
* the key's type
*/
public class WeakReferenceWithKey<K, R> extends WeakReference<R> {
private final K key;
private final Map<K, WeakReferenceWithKey<K, R>> map;
private volatile boolean wasCleanedUp;
public WeakReferenceWithKey(K key, R referent, Map<K, WeakReferenceWithKey<K, R>> map, ReferenceQueue<? super R> q) {
super(referent, q);
this.wasCleanedUp = false;
this.key = key;
this.map = map;
this.map.put(key, this);
}
/**
* Assuming that this weak reference was entered into {@link #map} using key {@link
*/
public void cleanUp() {
if (!wasCleanedUp) {
this.map.remove(this.key);
wasCleanedUp = true;
}
}
}
+54
View File
@@ -0,0 +1,54 @@
package com.sap.sse.util;
import java.lang.ref.ReferenceQueue;
import java.util.Map;
public class WeakValueCache<K, V> {
private final Map<K, WeakReferenceWithKey<K, V>> map;
private final ReferenceQueue<V> queue;
public WeakValueCache(final Map<K, WeakReferenceWithKey<K, V>> map) {
this.map = map;
queue = new ReferenceQueue<>();
}
public V get(K k) {
purge();
WeakReferenceWithKey<K, V> result = map.get(k);
return result == null ? null : result.get();
}
public V put(K k, V v) {
purge();
final V result;
final WeakReferenceWithKey<K, V> old = map.get(k);
if (old != null) {
old.cleanUp();
result = old.get();
} else {
result = null;
}
map.put(k, new WeakReferenceWithKey<>(k, v, map, queue));
return result;
}
public V remove(K k) {
purge();
final V result;
final WeakReferenceWithKey<K, V> ref = map.get(k);
if (ref != null) {
result = ref.get();
ref.cleanUp();
} else {
result = null;
}
return result;
}
private void purge() {
WeakReferenceWithKey<?, ?> r;
while ((r=(WeakReferenceWithKey<?, ?>) queue.poll()) != null) {
r.cleanUp();
}
}
}