Merge branch 'master' into import_dbdata

This commit is contained in:
Axel Uhl committed 2013-07-01 11:28:09 +02:00
commit 7221f071d9
8 files changed
+164 -89

No files matched your search

@@ -25,6 +25,8 @@ import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.util.impl.LockUtil;
import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
/**
* Manages a {@link LeaderboardCache}. When a {@link Leaderboard} is {@link LeaderboardCache#add added} to the cache, it
@@ -37,6 +39,7 @@ import com.sap.sailing.domain.tracking.Wind;
*/
public class LeaderboardCacheManager {
private final WeakHashMap<Leaderboard, CacheInvalidationUponScoreCorrectionListener> scoreCorrectionListeners;
private final NamedReentrantReadWriteLock scoreCorrectionListenersLock;
private final WeakHashMap<Leaderboard, Map<TrackedRace, Set<CacheInvalidationListener>>> invalidationListenersPerLeaderboard;
private final WeakHashMap<Leaderboard, RaceColumnListener> raceColumnListeners;
@@ -146,6 +149,7 @@ public class LeaderboardCacheManager {
this.invalidationListenersPerLeaderboard = new WeakHashMap<Leaderboard, Map<TrackedRace, Set<CacheInvalidationListener>>>();
this.raceColumnListeners = new WeakHashMap<Leaderboard, RaceColumnListener>();
this.scoreCorrectionListeners = new WeakHashMap<Leaderboard, CacheInvalidationUponScoreCorrectionListener>();
this.scoreCorrectionListenersLock = new NamedReentrantReadWriteLock("Score correction listeners", /* fair */ false);
}
private void removeFromCache(Leaderboard leaderboard) {
@@ -164,9 +168,14 @@ public class LeaderboardCacheManager {
synchronized (raceColumnListeners) {
leaderboard.removeRaceColumnListener(raceColumnListeners.remove(leaderboard));
}
synchronized (scoreCorrectionListeners) {
leaderboard.getScoreCorrection().removeScoreCorrectionListener(scoreCorrectionListeners.remove(leaderboard));
LockUtil.lockForWrite(scoreCorrectionListenersLock);
final CacheInvalidationUponScoreCorrectionListener removedScoreCorrectionListener;
try {
removedScoreCorrectionListener = scoreCorrectionListeners.remove(leaderboard);
} finally {
LockUtil.unlockAfterWrite(scoreCorrectionListenersLock);
}
leaderboard.getScoreCorrection().removeScoreCorrectionListener(removedScoreCorrectionListener);
}
public void add(Leaderboard leaderboard) {
@@ -181,108 +190,120 @@ public class LeaderboardCacheManager {
*/
private void registerAsListener(final Leaderboard leaderboard) {
// only add as listener again if not yet added
if (!scoreCorrectionListeners.containsKey(leaderboard)) {
for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) {
registerListener(leaderboard, trackedRace);
}
final CacheInvalidationUponScoreCorrectionListener scoreCorrectionListener = new CacheInvalidationUponScoreCorrectionListener(
leaderboard);
leaderboard.getScoreCorrection().addScoreCorrectionListener(scoreCorrectionListener);
synchronized (scoreCorrectionListeners) {
scoreCorrectionListeners.put(leaderboard, scoreCorrectionListener);
}
final RaceColumnListener raceColumnListener = new RaceColumnListener() {
private static final long serialVersionUID = 8165124797028386317L;
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
removeFromCache(leaderboard);
final boolean containsKey;
LockUtil.lockForRead(scoreCorrectionListenersLock);
try {
containsKey = scoreCorrectionListeners.containsKey(leaderboard);
} finally {
LockUtil.unlockAfterRead(scoreCorrectionListenersLock);
}
if (!containsKey) {
LockUtil.lockForWrite(scoreCorrectionListenersLock);
try {
for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) {
registerListener(leaderboard, trackedRace);
}
final CacheInvalidationUponScoreCorrectionListener scoreCorrectionListener = new CacheInvalidationUponScoreCorrectionListener(
leaderboard);
leaderboard.getScoreCorrection().addScoreCorrectionListener(scoreCorrectionListener);
scoreCorrectionListeners.put(leaderboard, scoreCorrectionListener);
final RaceColumnListener raceColumnListener = new RaceColumnListener() {
private static final long serialVersionUID = 8165124797028386317L;
/**
* This listener must not be serialized. See also bug 952.
*/
@Override
public boolean isTransient() {
return true;
}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
removeFromCache(leaderboard);
registerListener(leaderboard, trackedRace);
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
removeFromCache(leaderboard);
Map<TrackedRace, Set<CacheInvalidationListener>> listenersMap = invalidationListenersPerLeaderboard
.get(leaderboard);
if (listenersMap != null) {
Set<CacheInvalidationListener> listeners = listenersMap.get(trackedRace);
if (listeners != null) {
for (CacheInvalidationListener listener : listeners) {
listener.removeFromTrackedRace();
/**
* This listener must not be serialized. See also bug 952.
*/
@Override
public boolean isTransient() {
return true;
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
removeFromCache(leaderboard);
Map<TrackedRace, Set<CacheInvalidationListener>> listenersMap = invalidationListenersPerLeaderboard
.get(leaderboard);
if (listenersMap != null) {
Set<CacheInvalidationListener> listeners = listenersMap.get(trackedRace);
if (listeners != null) {
for (CacheInvalidationListener listener : listeners) {
listener.removeFromTrackedRace();
}
}
}
}
}
@Override
public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
removeFromCache(leaderboard);
}
@Override
public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
removeFromCache(leaderboard);
}
@Override
public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) {
removeFromCache(leaderboard);
}
@Override
public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) {
removeFromCache(leaderboard);
}
@Override
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) {
removeFromCache(leaderboard);
}
@Override
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn,
boolean firstColumnIsNonDiscardableCarryForward) {
removeFromCache(leaderboard);
}
@Override
public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
return true;
}
@Override
public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
return true;
}
@Override
public void raceColumnAddedToContainer(RaceColumn raceColumn) {
removeFromCache(leaderboard);
}
@Override
public void raceColumnAddedToContainer(RaceColumn raceColumn) {
removeFromCache(leaderboard);
}
@Override
public void raceColumnRemovedFromContainer(RaceColumn raceColumn) {
removeFromCache(leaderboard);
}
@Override
public void raceColumnRemovedFromContainer(RaceColumn raceColumn) {
removeFromCache(leaderboard);
}
@Override
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
removeFromCache(leaderboard);
}
@Override
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
removeFromCache(leaderboard);
}
@Override
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
removeFromCache(leaderboard);
}
@Override
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
removeFromCache(leaderboard);
}
@Override
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule, ResultDiscardingRule newDiscardingRule) {
removeFromCache(leaderboard);
}
@Override
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule,
ResultDiscardingRule newDiscardingRule) {
removeFromCache(leaderboard);
}
@Override
public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName,
String displayName) {
removeFromCache(leaderboard);
}
@Override
public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName,
String displayName) {
removeFromCache(leaderboard);
}
@Override
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier,
RaceLogEvent event) {
removeFromCache(leaderboard);
@Override
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier,
RaceLogEvent event) {
removeFromCache(leaderboard);
}
};
leaderboard.addRaceColumnListener(raceColumnListener);
synchronized (raceColumnListeners) {
raceColumnListeners.put(leaderboard, raceColumnListener);
}
};
leaderboard.addRaceColumnListener(raceColumnListener);
synchronized (raceColumnListeners) {
raceColumnListeners.put(leaderboard, raceColumnListener);
} finally {
LockUtil.unlockAfterWrite(scoreCorrectionListenersLock);
}
}
}
@@ -28,6 +28,7 @@ import com.sap.sailing.domain.leaderboard.ScoreCorrectionListener;
import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.util.impl.LockUtil;
import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
import com.sap.sailing.util.impl.ThreadFactoryWithPriority;
/**
@@ -53,6 +54,7 @@ public class LeaderboardDTOCache implements LeaderboardCache {
* all clients asking the same wait for the single result. Results are cached in this LRU-based evicting cache.
*/
private final Map<Util.Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>> leaderboardCache;
private final NamedReentrantReadWriteLock leaderboardCacheLock;
private int leaderboardByNameCacheHitCount;
private int leaderboardByNameCacheMissCount;
@@ -88,13 +90,17 @@ public class LeaderboardDTOCache implements LeaderboardCache {
return size() > 10; // remember 10 LeaderboardDTOs per leaderborad
}
};
leaderboardCacheLock = new NamedReentrantReadWriteLock("leaderboardCacheLock for "+leaderboard.getName(), /* fair */ false);
this.leaderboardCacheManager = new LeaderboardCacheManager(this);
}
@Override
public void invalidate(Leaderboard leaderboard) {
synchronized (leaderboardCache) {
LockUtil.lockForWrite(leaderboardCacheLock);
try {
leaderboardCache.clear();
} finally {
LockUtil.unlockAfterWrite(leaderboardCacheLock);
}
}
@@ -139,7 +145,12 @@ public class LeaderboardDTOCache implements LeaderboardCache {
* LeaderboardDTOCache. Therefore, it's okay to re-use the LeaderboardDTOCache match even if the latest analysis
* results are requested.
*/
future = leaderboardCache.get(key);
LockUtil.lockForRead(leaderboardCacheLock);
try {
future = leaderboardCache.get(key);
} finally {
LockUtil.unlockAfterRead(leaderboardCacheLock);
}
if (future == null) {
final Thread callerThread = Thread.currentThread();
future = new FutureTask<LeaderboardDTO>(new Callable<LeaderboardDTO>() {
@@ -159,8 +170,14 @@ public class LeaderboardDTOCache implements LeaderboardCache {
}
});
computeLeadearboardByNameExecutor.execute(future);
// The add(Leaderboard) method that the cache manager calls back on this class does nothing, so no synchronization required
this.leaderboardCacheManager.add(leaderboard); // ensure the leaderboard is tracked for changes to invalidate
leaderboardCache.put(key, future);
LockUtil.lockForWrite(leaderboardCacheLock);
try {
leaderboardCache.put(key, future);
} finally {
LockUtil.unlockAfterWrite(leaderboardCacheLock);
}
} else {
cacheHit = true;
}