mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-08 05:11:04 +00:00
used separate flags and logs for loading from windStore and gpSFixStore in tracked race
This commit is contained in:
1 parent
ab6ae2429d
commit
e022fe57e0
8 files changed
+88
-39
No files matched your search
+2
-1
@@ -221,7 +221,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
|
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
|
||||||
|
boolean notifyAboutGPSFixesAlreadyLoaded) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -353,7 +353,8 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
|
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
|
||||||
|
boolean notifyAboutGPSFixesAlreadyLoaded) {
|
||||||
// TODO Auto-generated method stub
|
// 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
|
* 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
|
* 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
|
* 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);
|
void removeListener(RaceChangeListener listener);
|
||||||
|
|
||||||
|
|||||||
+33
-9
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
|||||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||||
import com.sap.sailing.domain.tracking.GPSFix;
|
import com.sap.sailing.domain.tracking.GPSFix;
|
||||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
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.GPSTrackListener;
|
||||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
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
|
@Override
|
||||||
public void addListener(RaceChangeListener listener, final boolean notifyAboutWindFixesAlreadyLoaded) {
|
public void addListener(RaceChangeListener listener, final boolean notifyAboutWindFixesAlreadyLoaded,
|
||||||
|
final boolean notifyAboutGPSFixesAlreadyLoaded) {
|
||||||
if (notifyAboutWindFixesAlreadyLoaded) {
|
if (notifyAboutWindFixesAlreadyLoaded) {
|
||||||
LockUtil.lockForRead(getLoadingFromStoresLock());
|
LockUtil.lockForRead(getLoadingFromWindStoreLock());
|
||||||
|
}
|
||||||
|
if (notifyAboutGPSFixesAlreadyLoaded) {
|
||||||
|
LockUtil.lockForRead(getLoadingFromGPSFixStoreLock());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
addListener(listener);
|
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 {
|
} finally {
|
||||||
if (notifyAboutWindFixesAlreadyLoaded) {
|
if (notifyAboutWindFixesAlreadyLoaded) {
|
||||||
LockUtil.unlockAfterRead(getLoadingFromStoresLock());
|
LockUtil.unlockAfterRead(getLoadingFromWindStoreLock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-23
@@ -230,22 +230,31 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
private enum LoadingFromStoresState { NOT_STARTED, RUNNING, FINISHED };
|
private enum LoadingFromStoresState { NOT_STARTED, RUNNING, FINISHED };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constructor loads wind fixes from the {@link #windStore} and GPS fixes from the {@link #gpsFixStore}
|
* The constructor loads wind fixes from the {@link #windStore} asynchronously.
|
||||||
* asynchronously. When completed, this flag is set to <code>true</code>, and all threads currently waiting on this
|
* When completed all threads currently waiting on this object are notified.
|
||||||
* object are notified.
|
|
||||||
*/
|
*/
|
||||||
private LoadingFromStoresState loadingFromStoresCompleted;
|
private LoadingFromStoresState loadingFromWindStoreState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #loadingFromWindStoreState but for GPSFixStore
|
||||||
|
*/
|
||||||
|
private LoadingFromStoresState loadingFromGPSFixStoreState;
|
||||||
|
|
||||||
private transient CrossTrackErrorCache crossTrackErrorCache;
|
private transient CrossTrackErrorCache crossTrackErrorCache;
|
||||||
|
|
||||||
private final GPSFixStore gpsFixStore;
|
private final GPSFixStore gpsFixStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wind and GPS fix loading is started in a background thread during object construction. If a client needs to
|
* Wind and 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
|
* ensure that wind 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.
|
* 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;
|
private final Map<Iterable<MarkPassing>, NamedReentrantReadWriteLock> locksForMarkPassings;
|
||||||
|
|
||||||
@@ -257,7 +266,9 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
attachedRaceLogs = new HashMap<>();
|
attachedRaceLogs = new HashMap<>();
|
||||||
this.status = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0);
|
this.status = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0);
|
||||||
this.statusNotifier = new Object[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);
|
+ race.getName(), /* fair */ false);
|
||||||
this.cacheInvalidationTimerLock = new Object();
|
this.cacheInvalidationTimerLock = new Object();
|
||||||
this.updateCount = 0;
|
this.updateCount = 0;
|
||||||
@@ -314,15 +325,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
MarkPassingByTimeComparator.INSTANCE));
|
MarkPassingByTimeComparator.INSTANCE));
|
||||||
}
|
}
|
||||||
markPassingsTimes = new ArrayList<Pair<Waypoint, Pair<TimePoint, TimePoint>>>();
|
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.
|
// 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()) {
|
new Thread("Mongo wind loader for tracked race " + getRace().getName()) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LockUtil.lockForRead(getSerializationLock());
|
LockUtil.lockForRead(getSerializationLock());
|
||||||
LockUtil.lockForWrite(getLoadingFromStoresLock());
|
LockUtil.lockForWrite(getLoadingFromWindStoreLock());
|
||||||
synchronized (TrackedRaceImpl.this) {
|
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();
|
TrackedRaceImpl.this.notifyAll();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -335,10 +346,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
synchronized (TrackedRaceImpl.this) {
|
synchronized (TrackedRaceImpl.this) {
|
||||||
loadingFromStoresCompleted = LoadingFromStoresState.FINISHED;
|
loadingFromWindStoreState = LoadingFromStoresState.FINISHED;
|
||||||
TrackedRaceImpl.this.notifyAll();
|
TrackedRaceImpl.this.notifyAll();
|
||||||
|
loadingFromWindStoreState.notifyAll();
|
||||||
}
|
}
|
||||||
LockUtil.unlockAfterWrite(getLoadingFromStoresLock());
|
LockUtil.unlockAfterWrite(getLoadingFromWindStoreLock());
|
||||||
LockUtil.unlockAfterRead(getSerializationLock());
|
LockUtil.unlockAfterRead(getSerializationLock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +368,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
competitorRankingsLocks = new HashMap<TimePoint, NamedReentrantReadWriteLock>();
|
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
|
// now wait until wind loading has at least started; then we know that the serialization lock is safely held by the loader
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
while (loadingFromStoresCompleted != LoadingFromStoresState.FINISHED) {
|
while (loadingFromWindStoreState != LoadingFromStoresState.FINISHED) {
|
||||||
try {
|
try {
|
||||||
this.wait();
|
this.wait();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -418,7 +430,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void waitUntilLoadingFromStoresComplete() throws InterruptedException {
|
public synchronized void waitUntilLoadingFromStoresComplete() throws InterruptedException {
|
||||||
while (loadingFromStoresCompleted != LoadingFromStoresState.FINISHED) {
|
while (loadingFromWindStoreState != LoadingFromStoresState.FINISHED ||
|
||||||
|
loadingFromGPSFixStoreState != LoadingFromStoresState.FINISHED) {
|
||||||
wait();
|
wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2349,15 +2362,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
if (raceLog != null) {
|
if (raceLog != null) {
|
||||||
this.attachedRaceLogs.put(raceLog.getId(), raceLog);
|
this.attachedRaceLogs.put(raceLog.getId(), raceLog);
|
||||||
// Use the new race log, that possibly contains device mappings, to load GPSFix tracks from the DB
|
// 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.
|
// 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()) {
|
new Thread("Mongo mark and competitor track loader for tracked race " + getRace().getName()) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LockUtil.lockForRead(getSerializationLock());
|
LockUtil.lockForRead(getSerializationLock());
|
||||||
LockUtil.lockForWrite(getLoadingFromStoresLock());
|
LockUtil.lockForWrite(getLoadingFromWindStoreLock());
|
||||||
synchronized (TrackedRaceImpl.this) {
|
synchronized (TrackedRaceImpl.this) {
|
||||||
loadingFromStoresCompleted = LoadingFromStoresState.RUNNING; // indicates that the serialization
|
loadingFromGPSFixStoreState = LoadingFromStoresState.RUNNING; // indicates that the serialization
|
||||||
// lock is now safely held
|
// lock is now safely held
|
||||||
TrackedRaceImpl.this.notifyAll();
|
TrackedRaceImpl.this.notifyAll();
|
||||||
}
|
}
|
||||||
@@ -2378,10 +2391,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
synchronized (TrackedRaceImpl.this) {
|
synchronized (TrackedRaceImpl.this) {
|
||||||
loadingFromStoresCompleted = LoadingFromStoresState.FINISHED;
|
loadingFromGPSFixStoreState = LoadingFromStoresState.FINISHED;
|
||||||
TrackedRaceImpl.this.notifyAll();
|
TrackedRaceImpl.this.notifyAll();
|
||||||
|
loadingFromGPSFixStoreState.notifyAll();
|
||||||
}
|
}
|
||||||
LockUtil.unlockAfterWrite(getLoadingFromStoresLock());
|
LockUtil.unlockAfterWrite(getLoadingFromWindStoreLock());
|
||||||
LockUtil.unlockAfterRead(getSerializationLock());
|
LockUtil.unlockAfterRead(getSerializationLock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2544,8 +2558,12 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected NamedReentrantReadWriteLock getLoadingFromStoresLock() {
|
protected NamedReentrantReadWriteLock getLoadingFromWindStoreLock() {
|
||||||
return loadingFromStoresLock;
|
return loadingFromWindStoreLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NamedReentrantReadWriteLock getLoadingFromGPSFixStoreLock() {
|
||||||
|
return loadingFromGPSFixStoreLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-1
@@ -221,7 +221,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
|
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
|
||||||
|
boolean notifyAboutGPSFixesAlreadyLoaded) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1159,7 +1159,7 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
|
|||||||
}
|
}
|
||||||
TrackedRaceReplicator trackedRaceReplicator = new TrackedRaceReplicator(trackedRace);
|
TrackedRaceReplicator trackedRaceReplicator = new TrackedRaceReplicator(trackedRace);
|
||||||
trackedRaceReplicators.put(trackedRace, trackedRaceReplicator);
|
trackedRaceReplicators.put(trackedRace, trackedRaceReplicator);
|
||||||
trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */ true);
|
trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */ true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -327,7 +327,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
|
public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
|
||||||
|
boolean notifyAboutGPSFixesAlreadyLoaded) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user