java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java
... ...
@@ -196,7 +196,6 @@ import com.sap.sailing.domain.common.MarkType;
196 196
import com.sap.sailing.domain.common.MaxPointsReason;
197 197
import com.sap.sailing.domain.common.PassingInstruction;
198 198
import com.sap.sailing.domain.common.Position;
199
-import com.sap.sailing.domain.common.RaceFetcher;
200 199
import com.sap.sailing.domain.common.RaceIdentifier;
201 200
import com.sap.sailing.domain.common.RankingMetrics;
202 201
import com.sap.sailing.domain.common.RegattaName;
... ...
@@ -270,7 +269,6 @@ import com.sap.sailing.domain.tracking.TrackedRace;
270 269
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
271 270
import com.sap.sailing.domain.tracking.WindTrack;
272 271
import com.sap.sailing.domain.tracking.impl.ManeuverCurveBoundariesImpl;
273
-import com.sap.sailing.domain.tracking.impl.ManeuverImpl;
274 272
import com.sap.sailing.domain.tracking.impl.ManeuverWithMainCurveBoundariesImpl;
275 273
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
276 274
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
... ...
@@ -3427,8 +3425,4 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
3427 3425
ManeuverCurveBoundaries maneuverCurveBoundaries = new ManeuverCurveBoundariesImpl(timePointBefore, timePointAfter, SpeedWithBearingBefore, SpeedWithBearingAfter, directionChangeInDegrees, lowestSpeed, highestSpeed );
3428 3426
return maneuverCurveBoundaries;
3429 3427
}
3430
-
3431
-
3432
-
3433
-
3434 3428
}
... ...
\ No newline at end of file
java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java
... ...
@@ -128,16 +128,15 @@ import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
128 128
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
129 129
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
130 130
import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprint;
131
-import com.sap.sailing.domain.maneuverhash.MarkPassingProxy;
132 131
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprint;
133 132
import com.sap.sailing.domain.persistence.FieldNames;
134 133
import com.sap.sailing.domain.persistence.MongoObjectFactory;
135 134
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
136 135
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
137
-import com.sap.sailing.domain.tracking.MarkPassing;
138 136
import com.sap.sailing.domain.tracking.Maneuver;
139 137
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
140 138
import com.sap.sailing.domain.tracking.ManeuverLoss;
139
+import com.sap.sailing.domain.tracking.MarkPassing;
141 140
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
142 141
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
143 142
import com.sap.sailing.domain.tracking.TrackedRace;
java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java
... ...
@@ -137,7 +137,7 @@ public class AbstractGPSFixStoreTest extends RaceLogTrackingTestHelper {
137 137
/* endDate */null, null, null, "a", null, /* registrationLinkSecret */ UUID.randomUUID().toString()));
138 138
return new DynamicTrackedRaceImpl(regatta, raceDefinition, Collections.<Sideline> emptyList(),
139 139
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
140
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
140
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
141 141
}
142 142
143 143
protected void testNumberOfRawFixes(Track<?> track, long expected) {
java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/RaceLogFixTrackerManagerTest.java
... ...
@@ -97,7 +97,7 @@ public class RaceLogFixTrackerManagerTest {
97 97
/* registrationLinkSecret */ UUID.randomUUID().toString()));
98 98
trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections.<Sideline> emptyList(),
99 99
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
100
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
100
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
101 101
}
102 102
103 103
/**
java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java
... ...
@@ -171,7 +171,7 @@ public class SensorFixStoreAndLoadTest {
171 171
regatta.getRegatta().setControlTrackingFromStartAndFinishTimes(true);
172 172
trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections.<Sideline> emptyList(),
173 173
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
174
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
174
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
175 175
}
176 176
177 177
private void dropPersistedData() {
java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceStartTimeInferenceTest.java
... ...
@@ -85,7 +85,7 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
85 85
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
86 86
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
87 87
/* useMarkPassingCalculator */ false,
88
- OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
88
+ OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
89 89
90 90
MillisecondsTimePoint startOfRaceInRaceLog = new MillisecondsTimePoint(10000);
91 91
MillisecondsTimePoint endOfRaceInRaceLog = new MillisecondsTimePoint(20000);
... ...
@@ -163,7 +163,7 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
163 163
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
164 164
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
165 165
/* useMarkPassingCalculator */ false,
166
- OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
166
+ OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
167 167
trackedRace.attachRaceLog(raceLog);
168 168
final TimePoint[] oldAndNewStartTimeNotifiedByRace = new TimePoint[2];
169 169
trackedRace.addListener(new AbstractRaceChangeListener() {
... ...
@@ -208,7 +208,7 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
208 208
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
209 209
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
210 210
/* useMarkPassingCalculator */ false,
211
- OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
211
+ OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
212 212
final TimePoint[] oldAndNewStartTimeNotifiedByRace = new TimePoint[2];
213 213
trackedRace.addListener(new AbstractRaceChangeListener() {
214 214
@Override
... ...
@@ -257,7 +257,7 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
257 257
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
258 258
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
259 259
/* useMarkPassingCalculator */ false,
260
- OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
260
+ OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
261 261
trackedRace.attachRaceLog(raceLog);
262 262
trackedRace.attachRegattaLog(regattaLog);
263 263
final TimePoint[] newStartAndEndOfTrackingNotifiedByRace = new TimePoint[2];
... ...
@@ -365,7 +365,7 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
365 365
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
366 366
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
367 367
/* useMarkPassingCalculator */ false,
368
- OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
368
+ OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
369 369
trackedRace.attachRaceLog(raceLog);
370 370
final TimePoint[] oldAndNewStartTimeNotifiedByRace = new TimePoint[2];
371 371
trackedRace.addListener(new AbstractRaceChangeListener() {
java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java
... ...
@@ -355,7 +355,7 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl<RaceLogConne
355 355
boatClass.getApproximateManeuverDurationInMilliseconds(), null, /*useMarkPassingCalculator*/ true, raceLogResolver,
356 356
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty(),
357 357
new TrackingConnectorInfoImpl(RaceLogTrackingAdapter.NAME, RaceLogTrackingAdapter.DEFAULT_URL, /* no webUrl */ null),
358
- markPassingRaceFingerprintRegistry);
358
+ markPassingRaceFingerprintRegistry, /* maneuverRaceFingerprintRegistry */ null);
359 359
notifyRaceCreationListeners();
360 360
logger.info(String.format("Started tracking race-log race (%s)", raceLog));
361 361
// this wakes up all waiting race handles
java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java
... ...
@@ -545,7 +545,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl<SwissTim
545 545
}
546 546
}, useInternalMarkPassingAlgorithm, raceLogResolver,
547 547
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty(),
548
- new TrackingConnectorInfoImpl(SwissTimingAdapter.NAME, SwissTimingAdapter.DEFAULT_URL,/*no api connection to query the webUrl*/ null), markPassingRaceFingerprintRegistry);
548
+ new TrackingConnectorInfoImpl(SwissTimingAdapter.NAME, SwissTimingAdapter.DEFAULT_URL,/*no api connection to query the webUrl*/ null), markPassingRaceFingerprintRegistry,/*maneuverRaceFingerprintRegistry*/ null);
549 549
addUpdateHandlers();
550 550
notifyRaceCreationListeners();
551 551
logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName());
java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java
... ...
@@ -422,7 +422,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
422 422
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
423 423
/* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm, raceLogResolver,
424 424
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty(),
425
- new TrackingConnectorInfoImpl(SwissTimingAdapter.NAME, SwissTimingAdapter.DEFAULT_URL,/*no api connection to query the webUrl*/ null), markPassingRaceFingerprintRegistry);
425
+ new TrackingConnectorInfoImpl(SwissTimingAdapter.NAME, SwissTimingAdapter.DEFAULT_URL,/*no api connection to query the webUrl*/ null), markPassingRaceFingerprintRegistry, /*maneuverRaceFingerprintRegistry*/ null);
426 426
trackedRace.onStatusChanged(this, new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0));
427 427
TimePoint bestStartTimeKnownSoFar = bestStartTimePerRaceID.get(currentRaceID);
428 428
if (bestStartTimeKnownSoFar != null) {
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/markpassing/impl/WaypointPositionAndDistanceCacheTest.java
... ...
@@ -79,7 +79,7 @@ public class WaypointPositionAndDistanceCacheTest {
79 79
trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections.emptyList(), EmptyWindStore.INSTANCE,
80 80
/* delayToLiveInMillis */ 8000, /* millisecondsOverWhichToAverageWind */ 30000,
81 81
/* millisecondsOverWhichToAverageSpeed */ 15000, /* delayForCacheInvalidationOfWindEstimation */ 10000,
82
- /* useInternalMarkPassingAlgorithm */ false, OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null);
82
+ /* useInternalMarkPassingAlgorithm */ false, OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
83 83
timeRangeResolution = Duration.ONE_MINUTE;
84 84
now = new MillisecondsTimePoint(MillisecondsTimePoint.now().asMillis() / timeRangeResolution.asMillis() * timeRangeResolution.asMillis());
85 85
trackedRace.getOrCreateTrack(pinEnd).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.0000001), now));
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestCrossFleetScoring.java
... ...
@@ -144,7 +144,7 @@ public class TestCrossFleetScoring extends LeaderboardScoringAndRankingTestBase
144 144
/* delay for wind estimation cache invalidation */ 0, /* useMarkPassingCalculator */ false,
145 145
tr -> new TimeOnTimeAndDistanceRankingMetric(tr, timeOnTimeFactors, // time-on-time
146 146
c -> new MillisecondsDurationImpl((long) (1000. * timeOnDistanceAllowance.apply(c)))),
147
- mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null);
147
+ mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
148 148
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
149 149
DegreePosition topPosition = new DegreePosition(1, 0);
150 150
trackedRace.getOrCreateTrack(left)
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestFarthestAheadWithSkippedMarkPassing.java
... ...
@@ -128,7 +128,7 @@ public class TestFarthestAheadWithSkippedMarkPassing {
128 128
/* delayToLiveInMillis */ 0,
129 129
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
130 130
/* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false,
131
- tr->new OneDesignRankingMetric(tr), mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null);
131
+ tr->new OneDesignRankingMetric(tr), mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
132 132
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
133 133
DegreePosition topPosition = new DegreePosition(1, 0);
134 134
trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.000001), timePointForFixes));
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java
... ...
@@ -102,7 +102,7 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
102 102
/* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false,
103 103
tr->new TimeOnTimeAndDistanceRankingMetric(tr,
104 104
timeOnTimeFactors, // time-on-time
105
- c->new MillisecondsDurationImpl((long) (1000.*timeOnDistanceFactors.apply(c)))), mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null);
105
+ c->new MillisecondsDurationImpl((long) (1000.*timeOnDistanceFactors.apply(c)))), mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
106 106
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
107 107
DegreePosition topPosition = new DegreePosition(1, 0);
108 108
trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.000001), timePointForFixes));
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java
... ...
@@ -322,7 +322,7 @@ public class CourseTest {
322 322
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, /* delayToLiveInMillis */3000,
323 323
/* millisecondsOverWhichToAverageWind */30000,
324 324
/* millisecondsOverWhichToAverageSpeed */8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
325
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
325
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
326 326
assertLegStructure(course, trackedRace);
327 327
course.removeWaypoint(0);
328 328
assertLegStructure(course, trackedRace);
... ...
@@ -358,7 +358,7 @@ public class CourseTest {
358 358
EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 3000,
359 359
/* millisecondsOverWhichToAverageWind */ 30000,
360 360
/* millisecondsOverWhichToAverageSpeed */ 8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
361
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
361
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
362 362
assertLegStructure(course, trackedRace);
363 363
final WaypointImpl wp1_5 = new WaypointImpl(new MarkImpl("Test Mark 1.5"));
364 364
assertWaypointIndexes(course);
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java
... ...
@@ -88,7 +88,7 @@ public class CourseUpdateDuringNonAtomicSerializationTest implements Serializabl
88 88
EmptyWindStore.INSTANCE,
89 89
/* delayToLiveInMillis */10000, /* millisecondsOverWhichToAverageWind */30000, /* millisecondsOverWhichToAverageSpeed */
90 90
7000, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
91
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null) {
91
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null) {
92 92
private static final long serialVersionUID = 9114777576548711763L;
93 93
94 94
@Override
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java
... ...
@@ -140,7 +140,7 @@ public class LeaderboardCourseChangeTest {
140 140
TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace,
141 141
new HashSet<Sideline>(), EmptyWindStore.INSTANCE, 5000, 20000, 20000,
142 142
/* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
143
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null));
143
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null));
144 144
145 145
return spyedTrackedRace;
146 146
}
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceColumnCacheTest.java
... ...
@@ -130,7 +130,7 @@ public class RaceColumnCacheTest extends AbstractLeaderboardTest {
130 130
new HashSet<Sideline>(), EmptyWindStore.INSTANCE, 5000, 20000, 20000,
131 131
/* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
132 132
mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null,
133
- /* markPassingRaceFingerprintRegistry */ null));
133
+ /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null));
134 134
return spyedTrackedRace;
135 135
}
136 136
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java
... ...
@@ -119,7 +119,7 @@ public class ReachingLegTest extends TrackBasedTest {
119 119
/* delayToLiveInMillis */ 0,
120 120
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
121 121
/* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false,
122
- OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null);
122
+ OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
123 123
// in this simplified artificial course, the top mark is exactly north of the right leeward gate, the offset
124 124
// mark is slightly west of the top mark; wind from the north makes the leg from top to offset a reaching leg
125 125
Position leftPosition = new DegreePosition(0, -0.00001);
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java
... ...
@@ -42,7 +42,7 @@ public class SerializeRankingMetricTest extends AbstractSerializationTest {
42 42
new RaceDefinitionImpl("Race", new CourseImpl("Course", Collections.<Waypoint>emptyList()) ,
43 43
/* boatClass */ _49er, Collections.<Competitor,Boat>emptyMap()),
44 44
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0l, 0l, 0l,
45
- false, TimeOnTimeAndDistanceRankingMetric::new, null, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
45
+ false, TimeOnTimeAndDistanceRankingMetric::new, null, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* mneuverRaceFingerprintRegistry */ null);
46 46
RankingMetric clone = cloneBySerialization(trackedRace.getRankingMetric(), DomainFactory.INSTANCE);
47 47
assertNotNull(clone);
48 48
assertTrue(clone instanceof TimeOnTimeAndDistanceRankingMetric);
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java
... ...
@@ -91,7 +91,7 @@ public class StarbordSideOfStartLineRecognitionTest {
91 91
92 92
public MockedTrackedRaceImpl() {
93 93
super(null, null, Collections.<Sideline> emptyList(), null, 0, 0, 0, 0, false, OneDesignRankingMetric::new,
94
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
94
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
95 95
}
96 96
97 97
@Override
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java
... ...
@@ -201,7 +201,7 @@ public abstract class TrackBasedTest {
201 201
/* delayToLiveInMillis */ 0,
202 202
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
203 203
/* delay for wind estimation cache invalidation */ 0, useMarkPassingCalculator,
204
- rankingMetricConstructor, raceLogResolver, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
204
+ rankingMetricConstructor, raceLogResolver, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
205 205
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
206 206
DegreePosition topPosition = new DegreePosition(54.48, 10.24);
207 207
TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix timed
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java
... ...
@@ -53,7 +53,7 @@ public class UpdateMarkPassingTest {
53 53
race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, /* delayToLiveInMillis */1000,
54 54
/* millisecondsOverWhichToAverageWind */30000, /* millisecondsOverWhichToAverageSpeed */30000,
55 55
/* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
56
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
56
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
57 57
TimePoint now = MillisecondsTimePoint.now();
58 58
TimePoint later = now.plus(1000);
59 59
trackedRace.updateMarkPassings(competitor, Arrays.asList(new MarkPassing[] { new MarkPassingImpl(now, waypoint, competitor) }));
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationLockingUnderLoadTest.java
... ...
@@ -108,7 +108,7 @@ public class WindEstimationLockingUnderLoadTest {
108 108
/* sidelines */ Collections.emptySet(), EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 10000,
109 109
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 15000,
110 110
/* useInternalMarkPassingAlgorithm */ false, regatta.getRankingMetricConstructor(), /* raceLogResolver */ null,
111
- /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null) {
111
+ /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null) {
112 112
private static final long serialVersionUID = 1L;
113 113
114 114
@Override
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java
... ...
@@ -356,7 +356,7 @@ public class WindTest {
356 356
EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 1000,
357 357
/* millisecondsOverWhichToAverageWind */ 30000,
358 358
/* millisecondsOverWhichToAverageSpeed */ 30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
359
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
359
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
360 360
TimePoint start = MillisecondsTimePoint.now();
361 361
TimePoint topMarkRounding = start.plus(30000);
362 362
TimePoint finish = topMarkRounding.plus(30000);
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/maneuverhash/ManeuverRaceFingerprintJsonSerilizationTest.java
... ...
@@ -9,45 +9,26 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
9 9
10 10
import java.net.MalformedURLException;
11 11
import java.net.URISyntaxException;
12
-import java.util.HashMap;
13
-import java.util.Map;
14 12
import java.util.UUID;
15 13
16 14
import org.json.simple.JSONObject;
17 15
import org.junit.jupiter.api.BeforeEach;
18 16
import org.junit.jupiter.api.Test;
19 17
20
-import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
21
-import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
22
-import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
23
-import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFixedMarkPassingEventImpl;
24 18
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
25
-import com.sap.sailing.domain.abstractlog.race.impl.RaceLogSuppressedMarkPassingsEventImpl;
26 19
import com.sap.sailing.domain.base.Competitor;
27
-import com.sap.sailing.domain.base.ControlPoint;
28
-import com.sap.sailing.domain.base.ControlPointWithTwoMarks;
29
-import com.sap.sailing.domain.base.Mark;
30
-import com.sap.sailing.domain.base.Waypoint;
31
-import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
32
-import com.sap.sailing.domain.base.impl.MarkImpl;
33
-import com.sap.sailing.domain.base.impl.WaypointImpl;
34
-import com.sap.sailing.domain.common.PassingInstruction;
35 20
import com.sap.sailing.domain.common.Position;
36 21
import com.sap.sailing.domain.common.SpeedWithBearing;
37
-import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
38 22
import com.sap.sailing.domain.common.impl.DegreePosition;
39 23
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
40
-import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
41 24
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
42
-import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
43
-import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprint;
44 25
import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprint;
45 26
import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintFactory;
27
+import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
46 28
import com.sap.sailing.domain.test.OnlineTracTracBasedTest;
47 29
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
48 30
import com.sap.sailing.domain.tractracadapter.ReceiverType;
49 31
import com.sap.sse.common.TimePoint;
50
-import com.sap.sse.common.impl.MillisecondsTimePoint;
51 32
52 33
public class ManeuverRaceFingerprintJsonSerilizationTest extends OnlineTracTracBasedTest {
53 34
DynamicTrackedRaceImpl trackedRace1;
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractExportedPositionsBasedTest.java
... ...
@@ -107,7 +107,7 @@ public abstract class AbstractExportedPositionsBasedTest {
107 107
EmptyWindStore.INSTANCE,
108 108
/* delayToLiveInMillis */ 3000, /* millisecondsOverWhichToAverageWind */ 15000,
109 109
/* millisecondsOverWhichToAverageSpeed */ 10000, /* useInternalMarkPassingAlgorithm */ true,
110
- OneDesignRankingMetric::new, /* raceLogResolver */ null, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
110
+ OneDesignRankingMetric::new, /* raceLogResolver */ null, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
111 111
result.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0.0));
112 112
for (final Entry<CompetitorWithBoat, Iterable<GPSFixMoving>> e : competitorsAndTheirTracks.entrySet()) {
113 113
final DynamicGPSFixTrack<Competitor, GPSFixMoving> track = result.getTrack(e.getKey());
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java
... ...
@@ -88,7 +88,7 @@ public class AbstractMockedRaceMarkPassingTest {
88 88
race = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(r), raceDef, new ArrayList<Sideline>(),
89 89
new EmptyWindStore(), 0, 10000, 10000, /* useMarkPassingCalculator */ false,
90 90
OneDesignRankingMetric::new,
91
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
91
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */null);
92 92
race.setStartTimeReceived(new MillisecondsTimePoint(10000));
93 93
TimePoint t = new MillisecondsTimePoint(30000);
94 94
List<Util.Pair<Mark, Position>> pos = Arrays.asList(new Util.Pair<Mark, Position>(m, new DegreePosition(0, 0)),
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
... ...
@@ -55,6 +55,7 @@ import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuse
55 55
import com.sap.sailing.domain.leaderboard.impl.CompetitorAndRankComparable;
56 56
import com.sap.sailing.domain.leaderboard.impl.CompetitorProviderFromRaceColumnsAndRegattaLike;
57 57
import com.sap.sailing.domain.leaderboard.impl.RankAndRankComparable;
58
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
58 59
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
59 60
import com.sap.sailing.domain.polars.PolarDataService;
60 61
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
... ...
@@ -695,7 +696,7 @@ public class MockedTrackedRace implements DynamicTrackedRace {
695 696
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator,
696 697
RaceLogAndTrackedRaceResolver raceLogResolver,
697 698
Optional<ThreadLocalTransporter> threadLocalTransporter,
698
- TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
699
+ TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry ) {
699 700
return null;
700 701
}
701 702
... ...
@@ -1416,4 +1417,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
1416 1417
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
1417 1418
return null;
1418 1419
}
1419
-}
1420
+
1421
+ @Override
1422
+ public void updateManeuvers(Competitor competitor, Iterable<Maneuver> maneuvers) {
1423
+ }
1424
+}
... ...
\ No newline at end of file
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaTest.java
... ...
@@ -124,6 +124,6 @@ public class TrackedRegattaTest {
124 124
RaceDefinition race1 = new RaceDefinitionImpl(name, course, boatClass, Collections.emptyMap());
125 125
return new DynamicTrackedRaceImpl(regatta, race1, Collections.<Sideline> emptyList(),
126 126
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
127
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
127
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
128 128
}
129 129
}
java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
... ...
@@ -783,7 +783,7 @@ public class DomainFactoryImpl implements DomainFactory {
783 783
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
784 784
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
785 785
raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver, Optional.empty(),
786
- trackingConnectorInfo, markPassingRaceFingerprintRegistry);
786
+ trackingConnectorInfo, markPassingRaceFingerprintRegistry, /*maneuverRaceFingerprintRegistry*/ null);
787 787
}
788 788
789 789
/**
java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java
... ...
@@ -264,7 +264,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<IControlRoute,
264 264
/* ThreadLocalTransporter not needed because the RaceTracker is not active on a replica */ Optional
265 265
.empty(),
266 266
new TrackingConnectorInfoImpl(TracTracAdapter.NAME, TracTracAdapter.DEFAULT_URL,
267
- webUrlString), markPassingRaceFingerprintRegistry);
267
+ webUrlString), markPassingRaceFingerprintRegistry, /* maneuverRaceFingerprintRegistry */ null);
268 268
if (runAfterCreatingTrackedRace != null) {
269 269
runAfterCreatingTrackedRace.accept(trackedRace);
270 270
}
java/com.sap.sailing.domain.yellowbrickadapter/src/com/sap/sailing/domain/yellowbrickadapter/impl/YellowBrickRaceTrackerImpl.java
... ...
@@ -148,7 +148,7 @@ implements TrackingDataLoader {
148 148
}
149 149
}, /* useInternalMarkPassingAlgorithm */ true, raceLogResolver,
150 150
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty(),
151
- new TrackingConnectorInfoImpl(YellowBrickTrackingAdapter.NAME, "https://www.ybtracking.com/", /* TODO any default YB tracker URL? */ null), /* markPassingRaceFingerprintRegistry */ null);
151
+ new TrackingConnectorInfoImpl(YellowBrickTrackingAdapter.NAME, "https://www.ybtracking.com/", /* TODO any default YB tracker URL? */ null), /* markPassingRaceFingerprintRegistry */ null, /*maneuverRaceFingerprintRegistry*/ null);
152 152
addRaceLogListenerForCourseUpdates();
153 153
loadStoredData();
154 154
schedulePeriodicPollingTask();
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/MarkPassingProxy.java
... ...
@@ -4,7 +4,6 @@ import java.io.Serializable;
4 4
5 5
import com.sap.sailing.domain.base.Competitor;
6 6
import com.sap.sailing.domain.base.Waypoint;
7
-import com.sap.sailing.domain.common.RaceIdentifier;
8 7
import com.sap.sailing.domain.tracking.MarkPassing;
9 8
import com.sap.sailing.domain.tracking.TrackedRace;
10 9
import com.sap.sse.common.TimePoint;
... ...
@@ -36,8 +35,8 @@ public class MarkPassingProxy implements MarkPassing {
36 35
37 36
@Override
38 37
public TimePoint getTimePoint() {
39
- isMarkPassing();
40
- return markPassing.getTimePoint();
38
+// isMarkPassing();
39
+ return timePoint;
41 40
}
42 41
43 42
@Override
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverCacheDelegate.java
... ...
@@ -0,0 +1,197 @@
1
+package com.sap.sailing.domain.maneuverhash.impl;
2
+
3
+import java.util.ArrayList;
4
+import java.util.Collections;
5
+import java.util.List;
6
+import java.util.Map;
7
+import java.util.Set;
8
+import java.util.logging.Level;
9
+import java.util.logging.Logger;
10
+
11
+import com.sap.sailing.domain.base.CPUMeteringType;
12
+import com.sap.sailing.domain.base.Competitor;
13
+import com.sap.sailing.domain.common.NoWindException;
14
+import com.sap.sailing.domain.maneuverdetection.ManeuverDetector;
15
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprint;
16
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintFactory;
17
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
18
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
19
+import com.sap.sailing.domain.tracking.Maneuver;
20
+import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
21
+import com.sap.sse.common.Duration;
22
+import com.sap.sse.util.ManeuverCache;
23
+import com.sap.sse.util.SmartFutureCache;
24
+import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater;
25
+import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
26
+import com.sap.sse.util.SmartFutureCache.UpdateInterval;
27
+
28
+public class ManeuverCacheDelegate implements ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> {
29
+
30
+
31
+ private final TrackedRaceImpl race;
32
+ private static final Logger logger = Logger.getLogger(ManeuverCacheDelegate.class.getName());
33
+ private final ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry;
34
+ private ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> maneuverCache;
35
+ private ManeuverFromDatabase cache;
36
+ private SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval> smartFutureCache;
37
+ Map<Competitor, List<Maneuver>> maneuvers;
38
+// // flag suspended / resume
39
+ private boolean cachesSuspended;
40
+ private boolean triggerManeuverCacheInvalidationForAllCompetitors;
41
+
42
+ public ManeuverCacheDelegate(TrackedRaceImpl race,
43
+ ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
44
+ super();
45
+ this.race = race;
46
+ this.maneuverRaceFingerprintRegistry = maneuverRaceFingerprintRegistry;
47
+ this.cache = new ManeuverFromDatabase( false, race, maneuverRaceFingerprintRegistry);
48
+ this.smartFutureCache = new SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval>(
49
+ new AbstractCacheUpdater<Competitor, List<Maneuver>, EmptyUpdateInterval>() {
50
+ @Override
51
+ public List<Maneuver> computeCacheUpdate(Competitor competitor, EmptyUpdateInterval updateInterval)
52
+ throws NoWindException {
53
+ return race.getTrackedRegatta().callWithCPUMeterWithException(()->{
54
+ Duration averageIntervalBetweenRawFixes = race.getTrack(competitor).getAverageIntervalBetweenRawFixes();
55
+ if (averageIntervalBetweenRawFixes != null) {
56
+ ManeuverDetector maneuverDetector;
57
+ // FIXME The LowGPSSamplingRateManeuverDetectorImpl doesn't work very well; it recognizes many tacks only as bear-away and doesn't seem to have any noticeable benefits... See ORC Worlds 2019 ORC A Long Offshore
58
+ // if (averageIntervalBetweenRawFixes.asSeconds() >= 30) {
59
+ // maneuverDetector = new LowGPSSamplingRateManeuverDetectorImpl(TrackedRaceImpl.this, competitor);
60
+ // } else {
61
+ maneuverDetector = race.getManeuverDetectorPerCompetitorCache().getValue(competitor);
62
+
63
+ // }
64
+ List<Maneuver> maneuvers = race.computeManeuvers(competitor, maneuverDetector);
65
+ return maneuvers;
66
+ } else {
67
+ return Collections.emptyList();
68
+ }
69
+ }, CPUMeteringType.MANEUVER_DETECTION.name());
70
+ }
71
+ }, /* nameForLocks */ "Maneuver cache for race " + race.getRace().getName());
72
+ }
73
+
74
+ @Override
75
+ public void resume() {
76
+ // richtigen Ort bestimmen
77
+ if (triggerManeuverCacheInvalidationForAllCompetitors) {
78
+ triggerManeuverCacheRecalculationForAllCompetitors();
79
+ }
80
+
81
+ ManeuverRaceFingerprint fingerprint;
82
+ race.getRace().getCourse().lockForRead();
83
+ try {
84
+ synchronized (this) {
85
+ if (maneuverRaceFingerprintRegistry != null) {
86
+ fingerprint = maneuverRaceFingerprintRegistry.getManeuverRaceFingerprint(race.getRaceIdentifier());
87
+ } else {
88
+ fingerprint = null;
89
+ }
90
+ if (fingerprint != null && fingerprint.matches(race)) {
91
+ cache.resume();
92
+ } else {
93
+ new Thread(()->{
94
+ smartFutureCache.resume();
95
+ for(Competitor competitor : race.getRace().getCompetitors()) {
96
+ maneuvers.put(competitor, (List<Maneuver>) smartFutureCache.get(competitor, true));
97
+ }
98
+ maneuverRaceFingerprintRegistry.storeManeuvers(race.getRaceIdentifier(), ManeuverRaceFingerprintFactory.INSTANCE.createFingerprint(race), maneuvers, race.getRace().getCourse());
99
+ }, "Waiting for mark passings for "+race.getName()+" after having resumed to store the results in registry")
100
+ .start();
101
+ }
102
+ }
103
+ } finally {
104
+ race.getRace().getCourse().unlockAfterRead();
105
+ }
106
+ }
107
+
108
+ @Override
109
+ public List<Maneuver> get(Competitor competitor, boolean waitForLatest) {
110
+ ManeuverRaceFingerprint fingerprint;
111
+ race.getRace().getCourse().lockForRead();
112
+ try {
113
+ synchronized (this) {
114
+ if (maneuverRaceFingerprintRegistry != null) {
115
+ fingerprint = maneuverRaceFingerprintRegistry.getManeuverRaceFingerprint(race.getRaceIdentifier());
116
+ } else {
117
+ fingerprint = null;
118
+ }
119
+ if (fingerprint != null && fingerprint.matches(race)) {
120
+ return cache.get(competitor, waitForLatest);
121
+ } else {
122
+ return smartFutureCache.get(competitor, waitForLatest);
123
+ }
124
+ }
125
+ } finally {
126
+ race.getRace().getCourse().unlockAfterRead();
127
+ }
128
+ }
129
+
130
+ @Override
131
+ public void suspend() {
132
+ ManeuverRaceFingerprint fingerprint;
133
+ race.getRace().getCourse().lockForRead();
134
+ try {
135
+ synchronized (this) {
136
+ if (maneuverRaceFingerprintRegistry != null) {
137
+ fingerprint = maneuverRaceFingerprintRegistry.getManeuverRaceFingerprint(race.getRaceIdentifier());
138
+ } else {
139
+ fingerprint = null;
140
+ }
141
+ if (fingerprint != null && fingerprint.matches(race)) {
142
+ cache.suspend();
143
+ } else {
144
+ smartFutureCache.suspend();
145
+ }
146
+ }
147
+ } finally {
148
+ race.getRace().getCourse().unlockAfterRead();
149
+ }
150
+ }
151
+
152
+ @Override
153
+ public void triggerUpdate(Competitor competitor, EmptyUpdateInterval updateInterval) {
154
+ ManeuverRaceFingerprint fingerprint;
155
+ race.getRace().getCourse().lockForRead();
156
+ try {
157
+ synchronized (this) {
158
+ if (maneuverRaceFingerprintRegistry != null) {
159
+ fingerprint = maneuverRaceFingerprintRegistry.getManeuverRaceFingerprint(race.getRaceIdentifier());
160
+ } else {
161
+ fingerprint = null;
162
+ }
163
+ if (fingerprint != null && fingerprint.matches(race)) {
164
+ cache.triggerUpdate(competitor, updateInterval);
165
+ } else {
166
+ smartFutureCache.triggerUpdate(competitor, updateInterval);;
167
+ }
168
+ }
169
+ } finally {
170
+ race.getRace().getCourse().unlockAfterRead();
171
+ }
172
+ }
173
+
174
+
175
+ public void triggerManeuverCacheRecalculationForAllCompetitors() {
176
+ if (cachesSuspended) {
177
+ triggerManeuverCacheInvalidationForAllCompetitors = true;
178
+ } else {
179
+ final List<Competitor> shuffledCompetitors = new ArrayList<>();
180
+ for (Competitor competitor : (race.getRace().getCompetitors())) {
181
+ shuffledCompetitors.add(competitor);
182
+ }
183
+ Collections.shuffle(shuffledCompetitors);
184
+ for (Competitor competitor : shuffledCompetitors) {
185
+ triggerManeuverCacheRecalculation(competitor);
186
+ }
187
+ }
188
+ }
189
+
190
+ public void triggerManeuverCacheRecalculation(final Competitor competitor) {
191
+ if (cachesSuspended) {
192
+ triggerManeuverCacheInvalidationForAllCompetitors = true;
193
+ } else {
194
+ maneuverCache.triggerUpdate(competitor, /* updateInterval */null);
195
+ }
196
+ }
197
+}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverFromDatabase.java
... ...
@@ -0,0 +1,60 @@
1
+package com.sap.sailing.domain.maneuverhash.impl;
2
+
3
+import java.util.List;
4
+import java.util.Map;
5
+import java.util.logging.Level;
6
+import java.util.logging.Logger;
7
+
8
+import com.sap.sailing.domain.base.Competitor;
9
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
10
+import com.sap.sailing.domain.tracking.Maneuver;
11
+import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
12
+import com.sap.sse.util.ManeuverCache;
13
+import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
14
+
15
+public class ManeuverFromDatabase implements ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> {
16
+
17
+ public ManeuverFromDatabase(boolean suspended, TrackedRaceImpl race,
18
+ ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
19
+ super();
20
+ this.suspended = suspended;
21
+ this.race = race;
22
+ this.maneuverRaceFingerprintRegistry = maneuverRaceFingerprintRegistry;
23
+ }
24
+
25
+ boolean suspended;
26
+ private TrackedRaceImpl race;
27
+ private ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry;
28
+ private static final Logger logger = Logger.getLogger(ManeuverFromDatabase.class.getName());
29
+ Map<Competitor, List<Maneuver>> maneuvers;
30
+
31
+ public void resume() {
32
+ logger.info("Found stored set of maneuvers for race "+race.getName()+" with matching fingerprint; loading instead of computing...");
33
+ updateManeuversFromRegistry();
34
+ suspended = false;
35
+ }
36
+
37
+ private void updateManeuversFromRegistry() {
38
+ maneuvers = maneuverRaceFingerprintRegistry.loadManeuvers(race, race.getRace().getCourse());
39
+// for (final Entry<Competitor,List<Maneuver>> e : maneuverRaceFingerprintRegistry.loadManeuvers(
40
+// race, race.getRace().getCourse()).entrySet()) {
41
+//// race.updateManeuvers(e.getKey(), e.getValue().stream().sorted(TimedComparator.INSTANCE).collect(Collectors.toList()));
42
+// }
43
+ }
44
+
45
+ public void suspend() {
46
+ synchronized (this) {
47
+ logger.finest("Suspended ManeuverFromDatabase");
48
+ suspended = true;
49
+ }
50
+ }
51
+
52
+ public List<Maneuver> get(Competitor competitor, boolean waitForLatest) {
53
+ return maneuvers.get(competitor);
54
+ }
55
+
56
+ @Override
57
+ public void triggerUpdate(Competitor key, EmptyUpdateInterval updateInterval) {
58
+ logger.log(Level.WARNING, "If Fingerprint matches, no Update should be triggered");
59
+ }
60
+}
... ...
\ No newline at end of file
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverFromDatabaseTest.java
... ...
@@ -0,0 +1,64 @@
1
+package com.sap.sailing.domain.maneuverhash.impl;
2
+
3
+import java.util.List;
4
+import java.util.Map;
5
+import java.util.Map.Entry;
6
+import java.util.stream.Collectors;
7
+
8
+import com.sap.sailing.domain.base.Competitor;
9
+import com.sap.sailing.domain.base.Waypoint;
10
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprint;
11
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
12
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
13
+import com.sap.sailing.domain.tracking.Maneuver;
14
+import com.sap.sailing.domain.tracking.MarkPassing;
15
+import com.sap.sailing.domain.tracking.impl.TimedComparator;
16
+import com.sap.sse.util.SmartFutureCache;
17
+
18
+public class ManeuverFromDatabaseTest extends SmartFutureCache{
19
+ private final DynamicTrackedRace race;
20
+ private final ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry;
21
+
22
+ public ManeuverFromDatabaseTest(CacheUpdater cacheUpdateComputer, String nameForLocks,DynamicTrackedRace race, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry ) {
23
+ super(cacheUpdateComputer, nameForLocks);
24
+ this.race = race;
25
+ this.maneuverRaceFingerprintRegistry = maneuverRaceFingerprintRegistry;
26
+ // TODO Auto-generated constructor stub
27
+ }
28
+
29
+
30
+ public void resume() {
31
+ ManeuverRaceFingerprint fingerprint;
32
+ race.getRace().getCourse().lockForRead();
33
+ try {
34
+ synchronized (this) {
35
+ if (maneuverRaceFingerprintRegistry != null) {
36
+ fingerprint = maneuverRaceFingerprintRegistry.getManeuverRaceFingerprint(race.getRaceIdentifier());
37
+ } else {
38
+ fingerprint = null;
39
+ }
40
+ if (fingerprint != null && fingerprint.matches(race)) {
41
+
42
+ }
43
+
44
+ }
45
+
46
+ } finally {
47
+ race.getRace().getCourse().unlockAfterRead();
48
+ }
49
+ }
50
+
51
+ private void updateManeuversFromRegistry() {
52
+ Map<Competitor, List<Maneuver>> maneuvers = maneuverRaceFingerprintRegistry.loadManeuvers(
53
+ race, race.getRace().getCourse());
54
+ for (final Competitor e : maneuvers.keySet()) {
55
+ List<Maneuver> competitorManeuvers = maneuvers.get(e);
56
+
57
+ race.updateManeuvers(e, competitorManeuvers.stream().sorted(TimedComparator.INSTANCE).collect(Collectors.toList()));
58
+
59
+
60
+ }
61
+ }
62
+
63
+
64
+}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverRaceFingerprintImpl.java
... ...
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.maneuverhash.impl;
2 2
3 3
4 4
import java.util.Map;
5
+import java.util.stream.Collectors;
5 6
6 7
import org.json.simple.JSONObject;
7 8
... ...
@@ -224,7 +225,10 @@ public class ManeuverRaceFingerprintImpl implements ManeuverRaceFingerprint {
224 225
int res = 0;
225 226
String regattaName = trackedRace.getTrackedRegatta().getRegatta().getName();
226 227
Map<? extends WindSource, ? extends WindTrack> windTrack = trackedRace.getWindStore().loadWindTracks(regattaName, trackedRace, 10000);
227
- for (Map.Entry<? extends WindSource, ? extends WindTrack> w : windTrack.entrySet() ) {
228
+ Map<WindSource, WindTrack> gefilterteMap = windTrack.entrySet()
229
+ .stream().filter(entry -> entry.getKey().getType().isObserved())
230
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
231
+ for (Map.Entry<? extends WindSource, ? extends WindTrack> w : gefilterteMap.entrySet() ) {
228 232
int k = w.getKey().hashCode();
229 233
int v = w.getValue().hashCode();
230 234
res = res ^ k;
java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java
... ...
@@ -614,6 +614,7 @@ public class MarkPassingCalculator {
614 614
try {
615 615
latchForRunningListenRun.await();
616 616
final Map<Competitor, Map<Waypoint, MarkPassing>> markPassings = race.getMarkPassings(/* waitForLatestUpdates */ true);
617
+ // Bei Live-Rennen Speicherung unnötig
617 618
markPassingRaceFingerprintRegistry.storeMarkPassings(race.getRaceIdentifier(),
618 619
MarkPassingRaceFingerprintFactory.INSTANCE.createFingerprint(race),
619 620
markPassings, race.getRace().getCourse());
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrackedRace.java
... ...
@@ -131,6 +131,8 @@ public interface DynamicTrackedRace extends TrackedRace {
131 131
* for the finish line that are affected will be {@link #updateMarkPassings(Competitor, Iterable) updated}.
132 132
*/
133 133
void updateMarkPassingsAfterRaceLogChanges();
134
+
135
+ void updateManeuvers(Competitor competitor, Iterable<Maneuver> maneuvers);
134 136
135 137
/**
136 138
* Sets the start time as received from the tracking infrastructure. This isn't necessarily
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingHandler.java
... ...
@@ -18,6 +18,7 @@ import com.sap.sailing.domain.base.impl.DynamicCompetitor;
18 18
import com.sap.sailing.domain.base.impl.DynamicCompetitorWithBoat;
19 19
import com.sap.sailing.domain.base.impl.DynamicTeam;
20 20
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
21
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
21 22
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
22 23
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
23 24
import com.sap.sse.common.Color;
... ...
@@ -37,7 +38,7 @@ public interface RaceTrackingHandler {
37 38
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
38 39
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator,
39 40
RaceLogAndTrackedRaceResolver raceLogResolver, Optional<ThreadLocalTransporter> threadLocalTransporter,
40
- TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry);
41
+ TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry);
41 42
42 43
DynamicCompetitor getOrCreateCompetitor(CompetitorAndBoatStore competitorAndBoatStore, Serializable competitorId,
43 44
String name, String shortName, Color displayColor, String email, URI flagImageURI, DynamicTeam team,
... ...
@@ -61,10 +62,10 @@ public interface RaceTrackingHandler {
61 62
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
62 63
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator,
63 64
RaceLogAndTrackedRaceResolver raceLogResolver, Optional<ThreadLocalTransporter> threadLocalTransporter,
64
- TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
65
+ TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
65 66
return trackedRegatta.createTrackedRace(raceDefinition, sidelines, windStore, delayToLiveInMillis,
66 67
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate,
67
- useMarkPassingCalculator, raceLogResolver, threadLocalTransporter, trackingConnectorInfo, markPassingRaceFingerprintRegistry);
68
+ useMarkPassingCalculator, raceLogResolver, threadLocalTransporter, trackingConnectorInfo, markPassingRaceFingerprintRegistry, maneuverRaceFingerprintRegistry);
68 69
}
69 70
70 71
@Override
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java
... ...
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.base.Regatta;
10 10
import com.sap.sailing.domain.base.Sideline;
11 11
import com.sap.sailing.domain.base.impl.TrackedRaces;
12 12
import com.sap.sailing.domain.common.NoWindException;
13
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
13 14
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
14 15
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
15 16
import com.sap.sse.common.TimePoint;
... ...
@@ -70,7 +71,7 @@ public interface TrackedRegatta extends Serializable, HasCPUMeter {
70 71
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
71 72
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogAndTrackedRaceResolver raceLogResolver,
72 73
Optional<ThreadLocalTransporter> beforeAndAfterNotificationHandler, TrackingConnectorInfo trackingConnectorInfo,
73
- MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry);
74
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry);
74 75
75 76
/**
76 77
* Obtains the tracked race for <code>race</code>. Blocks until the tracked race has been created
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
... ...
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.common.racelog.Flags;
44 44
import com.sap.sailing.domain.common.tracking.GPSFix;
45 45
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
46 46
import com.sap.sailing.domain.common.tracking.SensorFix;
47
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
47 48
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
48 49
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
49 50
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
... ...
@@ -56,6 +57,7 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace;
56 57
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
57 58
import com.sap.sailing.domain.tracking.GPSFixTrack;
58 59
import com.sap.sailing.domain.tracking.GPSTrackListener;
60
+import com.sap.sailing.domain.tracking.Maneuver;
59 61
import com.sap.sailing.domain.tracking.MarkPassing;
60 62
import com.sap.sailing.domain.tracking.RaceAbortedListener;
61 63
import com.sap.sailing.domain.tracking.RaceChangeListener;
... ...
@@ -123,11 +125,11 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
123 125
long millisecondsOverWhichToAverageSpeed, long delayForCacheInvalidationOfWindEstimation,
124 126
boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor,
125 127
RaceLogAndTrackedRaceResolver raceLogResolver, TrackingConnectorInfo trackingConnectorInfo,
126
- MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
128
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
127 129
super(trackedRegatta, race, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
128 130
millisecondsOverWhichToAverageSpeed, delayForCacheInvalidationOfWindEstimation,
129 131
useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver, trackingConnectorInfo,
130
- markPassingRaceFingerprintRegistry);
132
+ markPassingRaceFingerprintRegistry, maneuverRaceFingerprintRegistry);
131 133
raceStateBasedStartTimeChangedListener = createRaceStateStartTimeChangeListener();
132 134
this.competitorResultsFromRaceLog = new HashMap<>();
133 135
this.logListener = new DynamicTrackedRaceLogListener(this);
... ...
@@ -209,11 +211,11 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
209 211
WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
210 212
long millisecondsOverWhichToAverageSpeed, boolean useInternalMarkPassingAlgorithm,
211 213
RankingMetricConstructor rankingMetricConstructor, RaceLogAndTrackedRaceResolver raceLogResolver, TrackingConnectorInfo trackingConnectorInfo,
212
- MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
214
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
213 215
this(trackedRegatta, race, sidelines, windStore, delayToLiveInMillis,
214 216
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
215 217
millisecondsOverWhichToAverageWind / 2, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver, trackingConnectorInfo,
216
- markPassingRaceFingerprintRegistry);
218
+ markPassingRaceFingerprintRegistry, maneuverRaceFingerprintRegistry);
217 219
}
218 220
219 221
@Override
... ...
@@ -337,7 +339,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
337 339
}
338 340
}
339 341
updated(/* time point */null);
340
- triggerManeuverCacheRecalculationForAllCompetitors();
342
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
341 343
}
342 344
343 345
@Override
... ...
@@ -348,7 +350,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
348 350
getOrCreateWindTrack(windSource).setMillisecondsOverWhichToAverage(millisecondsOverWhichToAverageWind);
349 351
}
350 352
updated(/* time point */null);
351
- triggerManeuverCacheRecalculationForAllCompetitors();
353
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
352 354
notifyListenersWindAveragingChanged(oldMillisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageWind);
353 355
}
354 356
... ...
@@ -405,7 +407,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
405 407
final GPSFix firstFixAfter = result.getFirstFixAfter(fixTimePoint);
406 408
invalidateDistancesFromStarboardSideOfStartLineProjectedOntoLineCache(TimeRange.create(lastFixBefore==null?null:lastFixBefore.getTimePoint(),
407 409
firstFixAfter==null?null:firstFixAfter.getTimePoint()));
408
- triggerManeuverCacheRecalculationForAllCompetitors();
410
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
409 411
notifyListeners(fix, mark, firstFixInTrack, addedOrReplaced);
410 412
}
411 413
... ...
@@ -922,7 +924,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
922 924
getRace().getCourse().unlockAfterRead();
923 925
}
924 926
updated(timePointOfLatestEvent);
925
- triggerManeuverCacheRecalculation(competitor);
927
+ maneuverCache.triggerManeuverCacheRecalculation(competitor);
926 928
// update the race times like start, end and the leg times
927 929
if (requiresStartTimeUpdate) {
928 930
invalidateStartTime();
... ...
@@ -935,6 +937,122 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
935 937
LockUtil.unlockAfterRead(getSerializationLock());
936 938
}
937 939
}
940
+
941
+
942
+ @Override
943
+ public void updateManeuvers(Competitor competitor, Iterable<Maneuver> maneuvers) {
944
+ final CompetitorResult resultFromRaceLog = competitorResultsFromRaceLog.get(competitor);
945
+ updateManeuversNotConsideringFinishingTimesFromRaceLog(competitor, maneuvers);
946
+ }
947
+
948
+
949
+
950
+
951
+
952
+
953
+ private void updateManeuversNotConsideringFinishingTimesFromRaceLog(Competitor competitor,
954
+ Iterable<Maneuver> maneuvers) {
955
+// LockUtil.lockForRead(getSerializationLock()); // keep serializer from reading the mark passings collections
956
+// try {
957
+// List<Maneuver> oldManeuvers = new ArrayList<Maneuver>();
958
+//// MarkPassing oldStartMarkPassing = null;
959
+// boolean requiresStartTimeUpdate = true;
960
+// final NavigableSet<Maneuver> maneuversForCompetitor = getManeuvers(competitor);
961
+// lockForRead(maneuversForCompetitor);
962
+// try {
963
+// for (MarkPassing oldMarkPassing : maneuversForCompetitor) {
964
+// if (oldStartMarkPassing == null) {
965
+// oldStartMarkPassing = oldMarkPassing;
966
+// }
967
+// oldMarkPassings.put(oldMarkPassing.getWaypoint(), oldMarkPassing);
968
+// }
969
+// } finally {
970
+// unlockAfterRead(maneuversForCompetitor);
971
+// }
972
+// final NamedReentrantReadWriteLock markPassingsLock = getMarkPassingsLock(maneuversForCompetitor);
973
+// TimePoint timePointOfLatestEvent = new MillisecondsTimePoint(0);
974
+// // Make sure that clearMarkPassings and the re-adding of the mark passings are non-interruptible by readers.
975
+// // Note that the write lock for the mark passings in order per waypoint is obtained inside
976
+// // clearMarkPassings(...) as well as inside the subsequent for-loop. It is important to always first obtain the mark passings lock
977
+// // for the competitor mark passings before obtaining the lock for the mark passings in order for the waypoint to avoid
978
+// // deadlocks.
979
+// getRace().getCourse().lockForRead();
980
+// LockUtil.lockForWrite(markPassingsLock);
981
+// try {
982
+// clearMarkPassings(competitor);
983
+// for (MarkPassing markPassing : markPassings) {
984
+// // Now since this caller of this update may not have held the course lock, mark passings
985
+// // may already be obsolete and for waypoints that no longer exist. Check:
986
+// if (getRace().getCourse().getIndexOfWaypoint(markPassing.getWaypoint()) >= 0) {
987
+// // try to find corresponding old start mark passing
988
+// if (oldStartMarkPassing != null
989
+// && markPassing.getWaypoint().equals(oldStartMarkPassing.getWaypoint())) {
990
+// if (markPassing.getTimePoint() != null && oldStartMarkPassing.getTimePoint() != null
991
+// && markPassing.getTimePoint().equals(oldStartMarkPassing.getTimePoint())) {
992
+// requiresStartTimeUpdate = false;
993
+// }
994
+// }
995
+// if (!Util.contains(getRace().getCourse().getWaypoints(), markPassing.getWaypoint())) {
996
+// StringBuilder courseWaypointsWithID = new StringBuilder();
997
+// boolean first = true;
998
+// for (Waypoint courseWaypoint : getRace().getCourse().getWaypoints()) {
999
+// if (first) {
1000
+// first = false;
1001
+// } else {
1002
+// courseWaypointsWithID.append(" -> ");
1003
+// }
1004
+// courseWaypointsWithID.append(courseWaypoint.toString());
1005
+// courseWaypointsWithID.append(" (ID=");
1006
+// courseWaypointsWithID.append(courseWaypoint.getId());
1007
+// courseWaypointsWithID.append(")");
1008
+// }
1009
+// logger.severe("Received mark passing " + markPassing + " for race " + getRace()
1010
+// + " for waypoint ID" + markPassing.getWaypoint().getId()
1011
+// + " but the waypoint does not exist in course " + courseWaypointsWithID);
1012
+// } else {
1013
+// markPassingsForCompetitor.add(markPassing);
1014
+// }
1015
+// Collection<MarkPassing> markPassingsInOrderForWaypoint = getOrCreateMarkPassingsInOrderAsNavigableSet(markPassing
1016
+// .getWaypoint());
1017
+// final NamedReentrantReadWriteLock markPassingsLock2 = getMarkPassingsLock(markPassingsInOrderForWaypoint);
1018
+// LockUtil.lockForWrite(markPassingsLock2);
1019
+// try {
1020
+// // The mark passings of competitor have been removed by the call to
1021
+// // clearMarkPassings(competitor) above
1022
+// // from both, the collection that holds the mark passings by waypoint and the one that holds the
1023
+// // mark passings per competitor; so we can simply add here:
1024
+// markPassingsInOrderForWaypoint.add(markPassing);
1025
+// } finally {
1026
+// LockUtil.unlockAfterWrite(markPassingsLock2);
1027
+// }
1028
+// if (markPassing.getTimePoint().compareTo(timePointOfLatestEvent) > 0) {
1029
+// timePointOfLatestEvent = markPassing.getTimePoint();
1030
+// }
1031
+// } else {
1032
+// logger.warning("Received mark passing "+markPassing+
1033
+// " for non-existing waypoint "+markPassing.getWaypoint()+
1034
+// " in race "+getRace().getName()+". Ignoring.");
1035
+// }
1036
+// }
1037
+// } finally {
1038
+// LockUtil.unlockAfterWrite(markPassingsLock);
1039
+// getRace().getCourse().unlockAfterRead();
1040
+// }
1041
+// updated(timePointOfLatestEvent);
1042
+// triggerManeuverCacheRecalculation(competitor);
1043
+// // update the race times like start, end and the leg times
1044
+// if (requiresStartTimeUpdate) {
1045
+// invalidateStartTime();
1046
+// }
1047
+// invalidateMarkPassingTimes();
1048
+// invalidateEndTime();
1049
+// // notify *after* all mark passings have been re-established; should avoid flicker
1050
+// notifyListeners(competitor, oldMarkPassings, markPassings);
1051
+// } finally {
1052
+// LockUtil.unlockAfterRead(getSerializationLock());
1053
+// }
1054
+
1055
+ }
938 1056
939 1057
/**
940 1058
* The {@link CompetitorResults} from the race log as cached in {@link #competitorResultsFromRaceLog} may optionally
... ...
@@ -1095,7 +1213,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
1095 1213
invalidateDistancesFromStarboardSideOfStartLineProjectedOntoLineCache(TimeRange.create(
1096 1214
fix.getTimePoint().minus(getMillisecondsOverWhichToAverageSpeed()),
1097 1215
fix.getTimePoint().plus(getMillisecondsOverWhichToAverageSpeed())));
1098
- triggerManeuverCacheRecalculation(competitor);
1216
+ maneuverCache.triggerManeuverCacheRecalculation(competitor);
1099 1217
notifyListeners(fix, competitor, addedOrReplaced);
1100 1218
// getAndSet call is atomic which means, that it can be ensured that the listeners are notified only once
1101 1219
final boolean oldGPSFixReceived = gpsFixReceived.getAndSet(true);
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java
... ...
@@ -1,9 +1,19 @@
1 1
package com.sap.sailing.domain.tracking.impl;
2 2
3
+import java.util.Optional;
4
+
3 5
import com.sap.sailing.domain.base.RaceDefinition;
4 6
import com.sap.sailing.domain.base.Regatta;
7
+import com.sap.sailing.domain.base.Sideline;
8
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
9
+import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
10
+import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
11
+import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
5 12
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
6 13
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
14
+import com.sap.sailing.domain.tracking.TrackingConnectorInfo;
15
+import com.sap.sailing.domain.tracking.WindStore;
16
+import com.sap.sse.util.ThreadLocalTransporter;
7 17
8 18
public class DynamicTrackedRegattaImpl extends TrackedRegattaImpl implements DynamicTrackedRegatta {
9 19
private static final long serialVersionUID = -90155868534737120L;
... ...
@@ -27,4 +37,16 @@ public class DynamicTrackedRegattaImpl extends TrackedRegattaImpl implements Dyn
27 37
public DynamicTrackedRace getExistingTrackedRace(RaceDefinition race) {
28 38
return (DynamicTrackedRace) super.getExistingTrackedRace(race);
29 39
}
40
+
41
+ @Override
42
+ public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines,
43
+ WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
44
+ long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
45
+ boolean useInternalMarkPassingAlgorithm, RaceLogAndTrackedRaceResolver raceLogResolver,
46
+ Optional<ThreadLocalTransporter> beforeAndAfterNotificationHandler,
47
+ TrackingConnectorInfo trackingConnectorInfo,
48
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
49
+ // TODO Auto-generated method stub
50
+ return null;
51
+ }
30 52
}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
... ...
@@ -133,6 +133,9 @@ import com.sap.sailing.domain.maneuverdetection.IncrementalManeuverDetector;
133 133
import com.sap.sailing.domain.maneuverdetection.ManeuverDetector;
134 134
import com.sap.sailing.domain.maneuverdetection.ShortTimeAfterLastHitCache;
135 135
import com.sap.sailing.domain.maneuverdetection.impl.IncrementalManeuverDetectorImpl;
136
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
137
+import com.sap.sailing.domain.maneuverhash.impl.ManeuverCacheDelegate;
138
+import com.sap.sailing.domain.maneuverhash.impl.ManeuverFromDatabase;
136 139
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
137 140
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
138 141
import com.sap.sailing.domain.orc.ORCPerformanceCurveRankingMetric;
... ...
@@ -188,6 +191,7 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
188 191
import com.sap.sse.shared.util.impl.ApproximateTime;
189 192
import com.sap.sse.shared.util.impl.ArrayListNavigableSet;
190 193
import com.sap.sse.util.IdentityWrapper;
194
+import com.sap.sse.util.ManeuverCache;
191 195
import com.sap.sse.util.SmartFutureCache;
192 196
import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater;
193 197
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
... ...
@@ -338,7 +342,9 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
338 342
* computed. Clients wanting to know maneuvers for the competitor outside of this time interval need to (re-)compute
339 343
* them.
340 344
*/
341
- private transient SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval> maneuverCache;
345
+ public transient ManeuverCacheDelegate maneuverCache;
346
+
347
+ private transient ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry;
342 348
343 349
/**
344 350
* The values of this map are used by the {@link #approximate(Competitor, Distance, TimePoint, TimePoint)} method and
... ...
@@ -494,11 +500,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
494 500
final WindStore windStore, long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
495 501
long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation,
496 502
boolean useInternalMarkPassingAlgorithm, RaceLogAndTrackedRaceResolver raceLogResolver, TrackingConnectorInfo trackingConnectorInfo,
497
- MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
503
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
498 504
this(trackedRegatta, race, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
499 505
millisecondsOverWhichToAverageSpeed, delayForWindEstimationCacheInvalidation,
500 506
useInternalMarkPassingAlgorithm, OneDesignRankingMetric::new, raceLogResolver, trackingConnectorInfo,
501
- markPassingRaceFingerprintRegistry);
507
+ markPassingRaceFingerprintRegistry, maneuverRaceFingerprintRegistry);
502 508
}
503 509
504 510
/**
... ...
@@ -518,7 +524,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
518 524
long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation,
519 525
boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor,
520 526
RaceLogAndTrackedRaceResolver raceLogResolver, TrackingConnectorInfo trackingConnectorInfo,
521
- MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
527
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
522 528
super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind);
523 529
distancesFromStarboardSideOfStartLineProjectedOntoLineCache = new ConcurrentHashMap<>();
524 530
distancesFromStarboardSideOfStartLineProjectedOntoLineCacheLastAccessTimes = new ConcurrentHashMap<>();
... ...
@@ -545,7 +551,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
545 551
this.delayToLiveInMillis = delayToLiveInMillis;
546 552
this.startToNextMarkCacheInvalidationListeners = new ConcurrentHashMap<Mark, TrackedRaceImpl.StartToNextMarkCacheInvalidationListener>();
547 553
this.maneuverDetectorPerCompetitorCache = createManeuverDetectorCache();
548
- this.maneuverCache = createManeuverCache();
554
+ this.maneuverCache = createManeuverCache(maneuverRaceFingerprintRegistry);
549 555
this.markTracks = new ConcurrentHashMap<Mark, GPSFixTrack<Mark, GPSFix>>();
550 556
int i = 0;
551 557
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
... ...
@@ -684,7 +690,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
684 690
result = windTrack.add(wind);
685 691
if (result) {
686 692
updated(wind.getTimePoint());
687
- triggerManeuverCacheRecalculationForAllCompetitors();
693
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
688 694
}
689 695
} else {
690 696
result = false;
... ...
@@ -696,7 +702,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
696 702
public void removeWind(Wind wind, WindSource windSource) {
697 703
getOrCreateWindTrack(windSource).remove(wind);
698 704
updated(/* time point */null); // wind events shouldn't advance race time
699
- triggerManeuverCacheRecalculationForAllCompetitors();
705
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
700 706
}
701 707
702 708
@Override
... ...
@@ -787,7 +793,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
787 793
competitorRankingsLocks = createCompetitorRankingsLockMap();
788 794
directionFromStartToNextMarkCache = new ConcurrentHashMap<>();
789 795
maneuverDetectorPerCompetitorCache = createManeuverDetectorCache();
790
- maneuverCache = createManeuverCache();
796
+ maneuverCache = createManeuverCache(maneuverRaceFingerprintRegistry);
791 797
logger.info("Deserialized race " + getRace().getName());
792 798
}
793 799
... ...
@@ -803,7 +809,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
803 809
} catch (PatchFailedException e) {
804 810
throw new RuntimeException(e);
805 811
} // a bit unclean: this also tries to work on the DynamicTrackedRaceImpl which isn't fully initialized yet; see also bug6039
806
- triggerManeuverCacheRecalculationForAllCompetitors(); // a bit unclean: this also tries to work on the DynamicTrackedRaceImpl which isn't fully initialized yet; see also bug6039
812
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); // a bit unclean: this also tries to work on the DynamicTrackedRaceImpl which isn't fully initialized yet; see also bug6039
807 813
}
808 814
809 815
/**
... ...
@@ -849,30 +855,35 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
849 855
competitor -> new IncrementalManeuverDetectorImpl(TrackedRaceImpl.this, competitor, windEstimation));
850 856
}
851 857
852
- private SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval> createManeuverCache() {
853
- return new SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval>(
854
- new AbstractCacheUpdater<Competitor, List<Maneuver>, EmptyUpdateInterval>() {
855
- @Override
856
- public List<Maneuver> computeCacheUpdate(Competitor competitor, EmptyUpdateInterval updateInterval)
857
- throws NoWindException {
858
- return getTrackedRegatta().callWithCPUMeterWithException(()->{
859
- Duration averageIntervalBetweenRawFixes = getTrack(competitor).getAverageIntervalBetweenRawFixes();
860
- if (averageIntervalBetweenRawFixes != null) {
861
- ManeuverDetector maneuverDetector;
862
- // FIXME The LowGPSSamplingRateManeuverDetectorImpl doesn't work very well; it recognizes many tacks only as bear-away and doesn't seem to have any noticeable benefits... See ORC Worlds 2019 ORC A Long Offshore
863
- // if (averageIntervalBetweenRawFixes.asSeconds() >= 30) {
864
- // maneuverDetector = new LowGPSSamplingRateManeuverDetectorImpl(TrackedRaceImpl.this, competitor);
865
- // } else {
866
- maneuverDetector = maneuverDetectorPerCompetitorCache.getValue(competitor);
867
- // }
868
- List<Maneuver> maneuvers = computeManeuvers(competitor, maneuverDetector);
869
- return maneuvers;
870
- } else {
871
- return Collections.emptyList();
872
- }
873
- }, CPUMeteringType.MANEUVER_DETECTION.name());
874
- }
875
- }, /* nameForLocks */ "Maneuver cache for race " + getRace().getName());
858
+ private ManeuverCacheDelegate createManeuverCache(ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
859
+ return new ManeuverCacheDelegate(this, maneuverRaceFingerprintRegistry);
860
+
861
+
862
+// new ManeuverFromDatabase(false, this, maneuverRaceFingerprintRegistry),
863
+// new SmartFutureCache(
864
+// new AbstractCacheUpdater<Competitor, List<Maneuver>, EmptyUpdateInterval>() {
865
+// @Override
866
+// public List<Maneuver> computeCacheUpdate(Competitor competitor, EmptyUpdateInterval updateInterval)
867
+// throws NoWindException {
868
+// return getTrackedRegatta().callWithCPUMeterWithException(()->{
869
+// Duration averageIntervalBetweenRawFixes = getTrack(competitor).getAverageIntervalBetweenRawFixes();
870
+// if (averageIntervalBetweenRawFixes != null) {
871
+// ManeuverDetector maneuverDetector;
872
+// // FIXME The LowGPSSamplingRateManeuverDetectorImpl doesn't work very well; it recognizes many tacks only as bear-away and doesn't seem to have any noticeable benefits... See ORC Worlds 2019 ORC A Long Offshore
873
+// // if (averageIntervalBetweenRawFixes.asSeconds() >= 30) {
874
+// // maneuverDetector = new LowGPSSamplingRateManeuverDetectorImpl(TrackedRaceImpl.this, competitor);
875
+// // } else {
876
+// maneuverDetector = maneuverDetectorPerCompetitorCache.getValue(competitor);
877
+// // }
878
+// List<Maneuver> maneuvers = computeManeuvers(competitor, maneuverDetector);
879
+// return maneuvers;
880
+// } else {
881
+// return Collections.emptyList();
882
+// }
883
+// }, CPUMeteringType.MANEUVER_DETECTION.name());
884
+// }
885
+// }, /* nameForLocks */ "Maneuver cache for race " + getRace().getName());
886
+
876 887
}
877 888
878 889
/**
... ...
@@ -2119,7 +2130,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
2119 2130
}
2120 2131
if (!old.equals(new HashSet<>(getWindSourcesToExclude()))) {
2121 2132
clearAllCachesExceptManeuvers();
2122
- triggerManeuverCacheRecalculationForAllCompetitors();
2133
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
2123 2134
}
2124 2135
}
2125 2136
... ...
@@ -2468,7 +2479,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
2468 2479
} finally {
2469 2480
LockUtil.unlockAfterWrite(getMarkPassingsLock(markPassingsForOneCompetitor));
2470 2481
}
2471
- triggerManeuverCacheRecalculation(competitor);
2482
+ maneuverCache.triggerManeuverCacheRecalculation(competitor);
2472 2483
}
2473 2484
}
2474 2485
logger.info("done updating tracked race "+this+"'s data structures...");
... ...
@@ -2882,30 +2893,30 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
2882 2893
return maneuverApproximators.get(competitor).approximate(from, to);
2883 2894
}
2884 2895
2885
- protected void triggerManeuverCacheRecalculationForAllCompetitors() {
2886
- if (cachesSuspended) {
2887
- triggerManeuverCacheInvalidationForAllCompetitors = true;
2888
- } else {
2889
- final List<Competitor> shuffledCompetitors = new ArrayList<>();
2890
- for (Competitor competitor : (getRace().getCompetitors())) {
2891
- shuffledCompetitors.add(competitor);
2892
- }
2893
- Collections.shuffle(shuffledCompetitors);
2894
- for (Competitor competitor : shuffledCompetitors) {
2895
- triggerManeuverCacheRecalculation(competitor);
2896
- }
2897
- }
2898
- }
2899
-
2900
- public void triggerManeuverCacheRecalculation(final Competitor competitor) {
2901
- if (cachesSuspended) {
2902
- triggerManeuverCacheInvalidationForAllCompetitors = true;
2903
- } else {
2904
- maneuverCache.triggerUpdate(competitor, /* updateInterval */null);
2905
- }
2906
- }
2907
-
2908
- private List<Maneuver> computeManeuvers(Competitor competitor, ManeuverDetector maneuverDetector)
2896
+// protected void triggerManeuverCacheRecalculationForAllCompetitors() {
2897
+// if (cachesSuspended) {
2898
+// triggerManeuverCacheInvalidationForAllCompetitors = true;
2899
+// } else {
2900
+// final List<Competitor> shuffledCompetitors = new ArrayList<>();
2901
+// for (Competitor competitor : (getRace().getCompetitors())) {
2902
+// shuffledCompetitors.add(competitor);
2903
+// }
2904
+// Collections.shuffle(shuffledCompetitors);
2905
+// for (Competitor competitor : shuffledCompetitors) {
2906
+// triggerManeuverCacheRecalculation(competitor);
2907
+// }
2908
+// }
2909
+// }
2910
+//
2911
+// public void triggerManeuverCacheRecalculation(final Competitor competitor) {
2912
+// if (cachesSuspended) {
2913
+// triggerManeuverCacheInvalidationForAllCompetitors = true;
2914
+// } else {
2915
+// maneuverCache.triggerUpdate(competitor, /* updateInterval */null);
2916
+// }
2917
+// }
2918
+
2919
+ public List<Maneuver> computeManeuvers(Competitor competitor, ManeuverDetector maneuverDetector)
2909 2920
throws NoWindException {
2910 2921
logger.finest("computeManeuvers(" + competitor.getName() + ") called in tracked race " + this);
2911 2922
long startedAt = System.currentTimeMillis();
... ...
@@ -3135,9 +3146,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
3135 3146
markPassingCalculator.resume();
3136 3147
}
3137 3148
crossTrackErrorCache.resume();
3138
- if (triggerManeuverCacheInvalidationForAllCompetitors) {
3139
- triggerManeuverCacheRecalculationForAllCompetitors();
3140
- }
3149
+
3150
+// if (triggerManeuverCacheInvalidationForAllCompetitors) {
3151
+// maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
3152
+// }
3153
+
3141 3154
maneuverCache.resume();
3142 3155
}
3143 3156
... ...
@@ -4087,7 +4100,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
4087 4100
// complete maneuver curves can be fed directly into the windEstimation.
4088 4101
maneuverDetectorPerCompetitorCache.clearCache();
4089 4102
shortTimeWindCache.clearCache();
4090
- triggerManeuverCacheRecalculationForAllCompetitors();
4103
+ maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors();
4091 4104
}
4092 4105
4093 4106
/**
... ...
@@ -4431,4 +4444,9 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
4431 4444
}
4432 4445
return result;
4433 4446
}
4447
+
4448
+ public ShortTimeAfterLastHitCache<Competitor, IncrementalManeuverDetector> getManeuverDetectorPerCompetitorCache() {
4449
+ return maneuverDetectorPerCompetitorCache;
4450
+
4451
+ }
4434 4452
}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java
... ...
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
22 22
import com.sap.sailing.domain.base.Regatta;
23 23
import com.sap.sailing.domain.base.Sideline;
24 24
import com.sap.sailing.domain.common.NoWindException;
25
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
25 26
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
26 27
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
27 28
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
... ...
@@ -323,13 +324,13 @@ public abstract class TrackedRegattaImpl implements TrackedRegatta {
323 324
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
324 325
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogAndTrackedRaceResolver raceLogResolver,
325 326
Optional<ThreadLocalTransporter> threadLocalTransporter, TrackingConnectorInfo trackingConnectorInfo,
326
- MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
327
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry,ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry ) {
327 328
logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition " + raceDefinition.getName());
328 329
DynamicTrackedRaceImpl result = new DynamicTrackedRaceImpl(this, raceDefinition, sidelines, windStore,
329 330
delayToLiveInMillis, millisecondsOverWhichToAverageWind,
330 331
millisecondsOverWhichToAverageSpeed,
331 332
/* useMarkPassingCalculator */useInternalMarkPassingAlgorithm, getRegatta().getRankingMetricConstructor(), raceLogResolver,
332
- trackingConnectorInfo, markPassingRaceFingerprintRegistry);
333
+ trackingConnectorInfo, markPassingRaceFingerprintRegistry, maneuverRaceFingerprintRegistry);
333 334
// adding the raceDefinition to the raceDefinitionSetToUpdate BEFORE calling addTrackedRace helps those who
334 335
// are called back by RaceListener.raceAdded(TrackedRace) and who then expect the update to have happened
335 336
if (raceDefinitionSetToUpdate != null) {
java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java
... ...
@@ -107,7 +107,7 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
107 107
public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) {
108 108
}
109 109
}, /*useMarkPassingCalculator*/ false, mock(RaceLogAndTrackedRaceResolver.class),
110
- Optional.empty(), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
110
+ Optional.empty(), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /*maneuverRaceFingerprintRegistry*/ null);
111 111
WindSource windSource = new WindSourceImpl(WindSourceType.WEB);
112 112
MongoClient myFirstMongo = newMongo();
113 113
MongoDatabase firstDatabase = myFirstMongo.getDatabase(dbConfiguration.getDatabaseName());
java/com.sap.sailing.server.test/src/com/sap/sailing/server/statistics/StatisticsTest.java
... ...
@@ -84,7 +84,7 @@ public class StatisticsTest {
84 84
85 85
trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections.<Sideline>emptyList(),
86 86
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
87
- mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
87
+ mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
88 88
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(START_OF_TRACKING));
89 89
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(END_OF_TRACKING));
90 90
trackedRace.setStartTimeReceived(new MillisecondsTimePoint(START_OF_RACE));
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java
... ...
@@ -140,7 +140,7 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest
140 140
/* delayToLiveInMillis */ 5000, /* millisecondsOverWhichToAverageWind */ 15000,
141 141
/* millisecondsOverWhichToAverageSpeed */ 10000,
142 142
/* useInternalMarkPassingAlgorithm */ false, OneDesignRankingMetric::new,
143
- /* raceLogResolver */ service, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
143
+ /* raceLogResolver */ service, /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
144 144
final Fleet fleet = f1Column.getFleets().iterator().next();
145 145
f1Column.setTrackedRace(fleet, newF1);
146 146
// Now add a CompetitorResult to the race log:
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java
... ...
@@ -90,19 +90,19 @@ public class RaceTrackerStartStopTest {
90 90
/* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l,
91 91
/* millisecondsOverWhichToAverageWind */ 0l,
92 92
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogAndTrackedRaceResolver.class),
93
- Optional.empty(), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
93
+ Optional.empty(), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
94 94
regatta.addRace(raceDef2);
95 95
trackedRegatta1.createTrackedRace(raceDef2, Collections.<Sideline> emptyList(),
96 96
/* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l,
97 97
/* millisecondsOverWhichToAverageWind */ 0l,
98 98
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogAndTrackedRaceResolver.class),
99
- Optional.empty(), null, /* markPassingRaceFingerprintRegistry */ null);
99
+ Optional.empty(), null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
100 100
regatta.addRace(raceDef3);
101 101
trackedRegatta1.createTrackedRace(raceDef3, Collections.<Sideline> emptyList(),
102 102
/* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l,
103 103
/* millisecondsOverWhichToAverageWind */ 0l,
104 104
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogAndTrackedRaceResolver.class),
105
- Optional.empty(), null, /* markPassingRaceFingerprintRegistry */ null);
105
+ Optional.empty(), null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
106 106
Long trackerID1 = Long.valueOf(1);
107 107
Long trackerID2 = Long.valueOf(2);
108 108
Long trackerID3 = Long.valueOf(3);
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardTest.java
... ...
@@ -104,7 +104,7 @@ public class RemoveLeaderboardTest {
104 104
/* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l,
105 105
/* millisecondsOverWhichToAverageWind */ 0l, /* millisecondsOverWhichToAverageSpeed */ 0l,
106 106
/* raceDefinitionSetToUpdate */ null, /* useMarkPassingCalculator */ false,
107
- mock(RaceLogAndTrackedRaceResolver.class), Optional.empty(), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
107
+ mock(RaceLogAndTrackedRaceResolver.class), Optional.empty(), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
108 108
}
109 109
110 110
@Test
java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/JumpyTrackSmootheningTest.java
... ...
@@ -317,7 +317,7 @@ public class JumpyTrackSmootheningTest {
317 317
final RaceDefinition race = new RaceDefinitionImpl(name, course, boatClass, competitorsAndTheirBoats, UUID.randomUUID());
318 318
return new DynamicTrackedRaceImpl(trackedRegatta, race, /* sidelines */ Collections.emptySet(), new EmptyWindStore(), /* delayToLiveInMillis */ 1000,
319 319
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, /* time over which to average speed: */ boatClass.getApproximateManeuverDurationInMilliseconds(),
320
- /* useInternalMarkPassingAlgorithm */ true, OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null);
320
+ /* useInternalMarkPassingAlgorithm */ true, OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null, /* maneuverRaceFingerprintRegistry */ null);
321 321
}
322 322
323 323
private Mark createAndPlaceMark(DynamicTrackedRace trackedRace, String name, String shortName, double latDeg, double lngDeg,
java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
... ...
@@ -197,6 +197,7 @@ import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardWithOtherTieBre
197 197
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
198 198
import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard;
199 199
import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprint;
200
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
200 201
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprint;
201 202
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
202 203
import com.sap.sailing.domain.orc.ORCPerformanceCurveRankingMetric;
... ...
@@ -1097,11 +1098,11 @@ Replicator {
1097 1098
DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
1098 1099
boolean useMarkPassingCalculator, RaceLogAndTrackedRaceResolver raceLogResolver,
1099 1100
Optional<ThreadLocalTransporter> threadLocalTransporter,
1100
- TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
1101
+ TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
1101 1102
final DynamicTrackedRace trackedRace = super.createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore,
1102 1103
delayToLiveInMillis, millisecondsOverWhichToAverageWind,
1103 1104
millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate,
1104
- useMarkPassingCalculator, raceLogResolver, threadLocalTransporter, trackingConnectorInfo, markPassingRaceFingerprintRegistry);
1105
+ useMarkPassingCalculator, raceLogResolver, threadLocalTransporter, trackingConnectorInfo, markPassingRaceFingerprintRegistry, maneuverRaceFingerprintRegistry);
1105 1106
getSecurityService().migrateOwnership(trackedRace);
1106 1107
trackedRace.runWhenDoneLoading(
1107 1108
()->numberOfTrackedRacesRestoredDoneLoading.incrementAndGet());
... ...
@@ -2256,7 +2257,7 @@ Replicator {
2256 2257
/* raceDefinitionSetToUpdate */null, useMarkPassingCalculator, /* raceLogResolver */ this,
2257 2258
Optional.of(this
2258 2259
.getThreadLocalTransporterForCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster()),
2259
- trackingConnectorInfo, /* markPassingRaceFingerprintRegistry */ this);
2260
+ trackingConnectorInfo, /* markPassingRaceFingerprintRegistry */ this, /* maneuverRaceFingerprintRegistry */ this);
2260 2261
}
2261 2262
2262 2263
private void ensureRegattaHasRaceAdditionListener(DynamicTrackedRegatta trackedRegatta) {
java/com.sap.sailing.server/src/com/sap/sailing/server/security/PermissionAwareRaceTrackingHandler.java
... ...
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.base.impl.DynamicTeam;
25 25
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
26 26
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
27 27
import com.sap.sailing.domain.common.security.SecuredDomainType;
28
+import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry;
28 29
import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry;
29 30
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
30 31
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
... ...
@@ -106,13 +107,13 @@ public class PermissionAwareRaceTrackingHandler extends DefaultRaceTrackingHandl
106 107
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
107 108
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator,
108 109
RaceLogAndTrackedRaceResolver raceLogResolver, Optional<ThreadLocalTransporter> threadLocalTransporter,
109
- TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) {
110
+ TrackingConnectorInfo trackingConnectorInfo, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
110 111
return setOwnershipForRace(
111 112
new RegattaNameAndRaceName(trackedRegatta.getRegatta().getName(), raceDefinition.getName()),
112 113
() -> super.createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore, delayToLiveInMillis,
113 114
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
114 115
raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver, threadLocalTransporter,
115
- trackingConnectorInfo, markPassingRaceFingerprintRegistry));
116
+ trackingConnectorInfo, markPassingRaceFingerprintRegistry,maneuverRaceFingerprintRegistry));
116 117
}
117 118
118 119
@Override
java/com.sap.sse/src/com/sap/sse/util/ManeuverCache.java
... ...
@@ -0,0 +1,15 @@
1
+package com.sap.sse.util;
2
+
3
+
4
+import com.sap.sse.util.SmartFutureCache.UpdateInterval;
5
+
6
+public interface ManeuverCache<K, V, U extends UpdateInterval<U>>{
7
+
8
+ void resume();
9
+
10
+ V get(K key, boolean waitForLatest);
11
+
12
+ void suspend();
13
+
14
+ void triggerUpdate(K key, U updateInterval);
15
+}
... ...
\ No newline at end of file
java/com.sap.sse/src/com/sap/sse/util/SmartFutureCache.java
... ...
@@ -77,7 +77,7 @@ import com.sap.sse.util.impl.KnowsExecutorAndTracingGetImpl;
77 77
* @author Axel Uhl (D043530)
78 78
*
79 79
*/
80
-public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
80
+public class SmartFutureCache<K, V, U extends UpdateInterval<U>> implements ManeuverCache<K, V, U> {
81 81
private static final Logger logger = Logger.getLogger(SmartFutureCache.class.getName());
82 82
83 83
/**
... ...
@@ -413,6 +413,7 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
413 413
}
414 414
}
415 415
416
+ @Override
416 417
public void suspend() {
417 418
logger.finest("suspending cache "+nameForLocks);
418 419
synchronized (ongoingRecalculations) {
... ...
@@ -420,6 +421,7 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
420 421
}
421 422
}
422 423
424
+ @Override
423 425
public void resume() {
424 426
synchronized (ongoingRecalculations) {
425 427
suspended = false;
... ...
@@ -457,6 +459,7 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
457 459
* If the running task has a different setting for the caller's waiting for the task, the task will be canceled
458 460
* (which may or may not work), and a new task with the joined update interval is scheduled.
459 461
*/
462
+ @Override
460 463
public void triggerUpdate(final K key, U updateInterval) {
461 464
// establish and maintain the following invariant: after lock on ongoingRecalculations is released,
462 465
// no Future contained in it is in cancelled state
... ...
@@ -672,6 +675,7 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
672 675
* ongoing, the result of that ongoing re-calculation is returned. When {@link #remove(Object)} has been called for the {@code key} and
673 676
* no update has finished computing since then, this method will also return {@code null} in case {@code waitForLatest} is {@code false}.
674 677
*/
678
+ @Override
675 679
public V get(final K key, boolean waitForLatest) {
676 680
final V value;
677 681
final Future<V> future;