used separate flags and logs for loading from windStore and gpSFixStore in tracked race

This commit is contained in:
Fredrik Teschke committed 2014-04-28 23:54:18 +02:00
1 parent ab6ae2429d
commit e022fe57e0
8 files changed
+88 -39

No files matched your search

@@ -221,7 +221,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}
@@ -353,7 +353,8 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
}
@Override
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}
@@ -443,9 +443,12 @@ public interface TrackedRace extends Serializable {
* tracked race. This runs synchronized with the otherwise asynchronous loading of wind tracks, triggered by the
* constructor of the {@link TrackedRace} implementation classes. This procedure guarantees that eventually the
* listener will have received a notification for all wind fixes, regardless of whether they were already loaded at
* the time the listener is registered or they are loaded after the registration has completed.
* the time the listener is registered or they are loaded after the registration has completed.<p>
*
* The same is true for the GPS fixes for marks and competitors.
*/
void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded);
void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
boolean notifyAboutGPSFixesAlreadyLoaded);
void removeListener(RaceChangeListener listener);
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.GPSTrackListener;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceChangeListener;
@@ -249,16 +250,14 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
}
}
/**
* If the listener wants to be notified about the wind fixes already loaded, this method will obtain the read lock
* of the {@link #getLoadingFromStoresLock() wind loading lock}, locking against the wind loading thread which uses the
* corresponding write lock. This ensures that either all wind fixes have been loaded already or that wind loading
* hasn't started yet.
*/
@Override
public void addListener(RaceChangeListener listener, final boolean notifyAboutWindFixesAlreadyLoaded) {
public void addListener(RaceChangeListener listener, final boolean notifyAboutWindFixesAlreadyLoaded,
final boolean notifyAboutGPSFixesAlreadyLoaded) {
if (notifyAboutWindFixesAlreadyLoaded) {
LockUtil.lockForRead(getLoadingFromStoresLock());
LockUtil.lockForRead(getLoadingFromWindStoreLock());
}
if (notifyAboutGPSFixesAlreadyLoaded) {
LockUtil.lockForRead(getLoadingFromGPSFixStoreLock());
}
try {
addListener(listener);
@@ -282,9 +281,34 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
}
}
}
if (notifyAboutGPSFixesAlreadyLoaded) {
for (Mark mark : getMarks()) {
GPSFixTrack<Mark, GPSFix> markTrack = getOrCreateTrack(mark);
markTrack.lockForRead();
try {
for (GPSFix fix : markTrack.getRawFixes()) {
listener.markPositionChanged(fix, mark);
}
} finally {
markTrack.unlockAfterRead();
}
}
for (Competitor competitor : getRace().getCompetitors()) {
GPSFixTrack<Competitor, GPSFixMoving> competitorTrack = getTrack(competitor);
competitorTrack.lockForRead();
try {
for (GPSFixMoving fix : competitorTrack.getRawFixes()) {
listener.competitorPositionChanged(fix, competitor);
}
} finally {
competitorTrack.unlockAfterRead();
}
}
}
} finally {
if (notifyAboutWindFixesAlreadyLoaded) {
LockUtil.unlockAfterRead(getLoadingFromStoresLock());
LockUtil.unlockAfterRead(getLoadingFromWindStoreLock());
}
}
}
@@ -230,22 +230,31 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
private enum LoadingFromStoresState { NOT_STARTED, RUNNING, FINISHED };
/**
* The constructor loads wind fixes from the {@link #windStore} and GPS fixes from the {@link #gpsFixStore}
* asynchronously. When completed, this flag is set to <code>true</code>, and all threads currently waiting on this
* object are notified.
* The constructor loads wind fixes from the {@link #windStore} asynchronously.
* When completed all threads currently waiting on this object are notified.
*/
private LoadingFromStoresState loadingFromStoresCompleted;
private LoadingFromStoresState loadingFromWindStoreState;
/**
* @see #loadingFromWindStoreState but for GPSFixStore
*/
private LoadingFromStoresState loadingFromGPSFixStoreState;
private transient CrossTrackErrorCache crossTrackErrorCache;
private final GPSFixStore gpsFixStore;
/**
* Wind and GPS fix loading is started in a background thread during object construction. If a client needs to
* ensure that wind / GPS fix loading either has terminated or has not yet begun, it can obtain the read lock of
* this lock. The wind / GPS fix loading procedure will obtain the write lock before it starts loading wind fixes.
* Wind and loading is started in a background thread during object construction. If a client needs to
* ensure that wind loading either has terminated or has not yet begun, it can obtain the read lock of
* this lock. The wind loading procedure will obtain the write lock before it starts loading wind fixes.
*/
private final NamedReentrantReadWriteLock loadingFromStoresLock;
private final NamedReentrantReadWriteLock loadingFromWindStoreLock;
/**
* @see #loadingFromWindStoreLock but for GPSFixStore
*/
private final NamedReentrantReadWriteLock loadingFromGPSFixStoreLock;
private final Map<Iterable<MarkPassing>, NamedReentrantReadWriteLock> locksForMarkPassings;
@@ -257,7 +266,9 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
attachedRaceLogs = new HashMap<>();
this.status = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0);
this.statusNotifier = new Object[0];
this.loadingFromStoresLock = new NamedReentrantReadWriteLock("Loading from stores lock for tracked race "
this.loadingFromWindStoreLock = new NamedReentrantReadWriteLock("Loading from wind store lock for tracked race "
+ race.getName(), /* fair */ false);
this.loadingFromGPSFixStoreLock = new NamedReentrantReadWriteLock("Loading from GPSFix store lock for tracked race "
+ race.getName(), /* fair */ false);
this.cacheInvalidationTimerLock = new Object();
this.updateCount = 0;
@@ -314,15 +325,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
MarkPassingByTimeComparator.INSTANCE));
}
markPassingsTimes = new ArrayList<Pair<Waypoint, Pair<TimePoint, TimePoint>>>();
loadingFromStoresCompleted = LoadingFromStoresState.NOT_STARTED;
loadingFromWindStoreState = LoadingFromStoresState.NOT_STARTED;
// When this tracked race is to be serialized, wait for the loading from stores to complete.
new Thread("Mongo wind loader for tracked race " + getRace().getName()) {
@Override
public void run() {
LockUtil.lockForRead(getSerializationLock());
LockUtil.lockForWrite(getLoadingFromStoresLock());
LockUtil.lockForWrite(getLoadingFromWindStoreLock());
synchronized (TrackedRaceImpl.this) {
loadingFromStoresCompleted = LoadingFromStoresState.RUNNING; // indicates that the serialization lock is now safely held
loadingFromWindStoreState = LoadingFromStoresState.RUNNING; // indicates that the serialization lock is now safely held
TrackedRaceImpl.this.notifyAll();
}
try {
@@ -335,10 +346,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
} finally {
synchronized (TrackedRaceImpl.this) {
loadingFromStoresCompleted = LoadingFromStoresState.FINISHED;
loadingFromWindStoreState = LoadingFromStoresState.FINISHED;
TrackedRaceImpl.this.notifyAll();
loadingFromWindStoreState.notifyAll();
}
LockUtil.unlockAfterWrite(getLoadingFromStoresLock());
LockUtil.unlockAfterWrite(getLoadingFromWindStoreLock());
LockUtil.unlockAfterRead(getSerializationLock());
}
}
@@ -356,7 +368,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
competitorRankingsLocks = new HashMap<TimePoint, NamedReentrantReadWriteLock>();
// now wait until wind loading has at least started; then we know that the serialization lock is safely held by the loader
synchronized (this) {
while (loadingFromStoresCompleted != LoadingFromStoresState.FINISHED) {
while (loadingFromWindStoreState != LoadingFromStoresState.FINISHED) {
try {
this.wait();
} catch (InterruptedException e) {
@@ -418,7 +430,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
@Override
public synchronized void waitUntilLoadingFromStoresComplete() throws InterruptedException {
while (loadingFromStoresCompleted != LoadingFromStoresState.FINISHED) {
while (loadingFromWindStoreState != LoadingFromStoresState.FINISHED ||
loadingFromGPSFixStoreState != LoadingFromStoresState.FINISHED) {
wait();
}
}
@@ -2349,15 +2362,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
if (raceLog != null) {
this.attachedRaceLogs.put(raceLog.getId(), raceLog);
// Use the new race log, that possibly contains device mappings, to load GPSFix tracks from the DB
loadingFromStoresCompleted = LoadingFromStoresState.NOT_STARTED;
loadingFromGPSFixStoreState = LoadingFromStoresState.NOT_STARTED;
// When this tracked race is to be serialized, wait for the loading from stores to complete.
new Thread("Mongo mark and competitor track loader for tracked race " + getRace().getName()) {
@Override
public void run() {
LockUtil.lockForRead(getSerializationLock());
LockUtil.lockForWrite(getLoadingFromStoresLock());
LockUtil.lockForWrite(getLoadingFromWindStoreLock());
synchronized (TrackedRaceImpl.this) {
loadingFromStoresCompleted = LoadingFromStoresState.RUNNING; // indicates that the serialization
loadingFromGPSFixStoreState = LoadingFromStoresState.RUNNING; // indicates that the serialization
// lock is now safely held
TrackedRaceImpl.this.notifyAll();
}
@@ -2378,10 +2391,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
} finally {
synchronized (TrackedRaceImpl.this) {
loadingFromStoresCompleted = LoadingFromStoresState.FINISHED;
loadingFromGPSFixStoreState = LoadingFromStoresState.FINISHED;
TrackedRaceImpl.this.notifyAll();
loadingFromGPSFixStoreState.notifyAll();
}
LockUtil.unlockAfterWrite(getLoadingFromStoresLock());
LockUtil.unlockAfterWrite(getLoadingFromWindStoreLock());
LockUtil.unlockAfterRead(getSerializationLock());
}
}
@@ -2544,8 +2558,12 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
return null;
}
protected NamedReentrantReadWriteLock getLoadingFromStoresLock() {
return loadingFromStoresLock;
protected NamedReentrantReadWriteLock getLoadingFromWindStoreLock() {
return loadingFromWindStoreLock;
}
protected NamedReentrantReadWriteLock getLoadingFromGPSFixStoreLock() {
return loadingFromGPSFixStoreLock;
}
/**
@@ -221,7 +221,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}
@@ -1159,7 +1159,7 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
}
TrackedRaceReplicator trackedRaceReplicator = new TrackedRaceReplicator(trackedRace);
trackedRaceReplicators.put(trackedRace, trackedRaceReplicator);
trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */ true);
trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */ true, true);
}
}
@@ -327,7 +327,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
}
@Override
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}