java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverCacheDelegate.java
... ...
@@ -20,87 +20,59 @@ public class ManeuverCacheDelegate implements ManeuverCache<Competitor, List<Man
20 20
private final TrackedRaceImpl race;
21 21
private static final Logger logger = Logger.getLogger(ManeuverCacheDelegate.class.getName());
22 22
private final ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry;
23
- private ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> cacheToUse;
23
+ private volatile ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> cacheToUse;
24 24
25 25
public ManeuverCacheDelegate(TrackedRaceImpl race,
26 26
ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) {
27 27
super();
28 28
this.race = race;
29 29
this.maneuverRaceFingerprintRegistry = maneuverRaceFingerprintRegistry;
30
- this.cacheToUse = new ManeuverFromSmartFutureCache((DynamicTrackedRaceImpl) race);
30
+ this.cacheToUse = new ManeuversFromSmartFutureCache((DynamicTrackedRaceImpl) race);
31 31
}
32 32
33 33
@Override
34 34
public void resume() {
35 35
final ManeuverRaceFingerprint fingerprint;
36
- race.getRace().getCourse().lockForRead();
37
- try {
38
- synchronized (this) {
36
+ if (maneuverRaceFingerprintRegistry != null) {
37
+ logger.info("Compare maneuver fingerprints for race "+race.getRaceIdentifier());
38
+ race.waitForAllRaceLogsAttached();
39
+ fingerprint = maneuverRaceFingerprintRegistry.getManeuverRaceFingerprint(race.getRaceIdentifier());
40
+ } else {
41
+ fingerprint = null;
42
+ }
43
+ if (fingerprint != null && fingerprint.matches(race)) {
44
+ logger.info("Maneuver fingerprints match for race "+race.getRaceIdentifier()+"; loading from DB instead of computing");
45
+ cacheToUse = new ManeuversFromDatabase(maneuverRaceFingerprintRegistry.loadManeuvers(race, race.getRace().getCourse()));
46
+ } else {
47
+ new Thread(()->{
48
+ logger.info("Maneuver fingerprints do not match for race "+race.getRaceIdentifier()+"; NOT loading from DB");
49
+ cacheToUse.resume();
39 50
if (maneuverRaceFingerprintRegistry != null) {
40
- logger.info("Compare maneuver fingerprints for race "+race.getRaceIdentifier());
41
- race.waitForAllRaceLogsAttached();
42
- fingerprint = maneuverRaceFingerprintRegistry.getManeuverRaceFingerprint(race.getRaceIdentifier());
43
- } else {
44
- fingerprint = null;
45
- }
46
- if (fingerprint != null && fingerprint.matches(race)) {
47
- logger.info("Maneuver fingerprints match for race "+race.getRaceIdentifier()+"; loading from DB instead of computing");
48
- cacheToUse = new ManeuversFromDatabase(maneuverRaceFingerprintRegistry.loadManeuvers(race, race.getRace().getCourse()));
49
- } else {
50
- new Thread(()->{
51
- logger.info("Maneuver fingerprints do not match for race "+race.getRaceIdentifier()+"; NOT loading from DB");
52
- cacheToUse.resume();
53
- if (maneuverRaceFingerprintRegistry != null) {
54
- // wait for maneuvers to be computed by the default cache implementation (SmartFutureCache),
55
- // then store persistently in registry
56
- final Map<Competitor, List<Maneuver>> maneuvers = new HashMap<>();
57
- for (final Competitor competitor : race.getRace().getCompetitors()) {
58
- maneuvers.put(competitor, (List<Maneuver>) cacheToUse.get(competitor, /* waitForLatest */ true));
59
- }
60
- maneuverRaceFingerprintRegistry.storeManeuvers(race.getRaceIdentifier(), ManeuverRaceFingerprintFactory.INSTANCE.createFingerprint(race), maneuvers, race.getRace().getCourse());
61
- }
62
- }, "Waiting for mark passings for "+race.getName()+" after having resumed to store the results in registry")
63
- .start();
51
+ // wait for maneuvers to be computed by the default cache implementation (SmartFutureCache),
52
+ // then store persistently in registry
53
+ final Map<Competitor, List<Maneuver>> maneuvers = new HashMap<>();
54
+ for (final Competitor competitor : race.getRace().getCompetitors()) {
55
+ maneuvers.put(competitor, (List<Maneuver>) cacheToUse.get(competitor, /* waitForLatest */ true));
56
+ }
57
+ maneuverRaceFingerprintRegistry.storeManeuvers(race.getRaceIdentifier(), ManeuverRaceFingerprintFactory.INSTANCE.createFingerprint(race), maneuvers, race.getRace().getCourse());
64 58
}
65
- }
66
- } finally {
67
- race.getRace().getCourse().unlockAfterRead();
59
+ }, "Waiting for mark passings for "+race.getName()+" after having resumed to store the results in registry")
60
+ .start();
68 61
}
69 62
}
70 63
71 64
@Override
72 65
public List<Maneuver> get(Competitor competitor, boolean waitForLatest) {
73
- race.getRace().getCourse().lockForRead();
74
- try {
75
- synchronized (this) {
76
- return (List<Maneuver>) cacheToUse.get(competitor, waitForLatest);
77
- }
78
- } finally {
79
- race.getRace().getCourse().unlockAfterRead();
80
- }
66
+ return cacheToUse.get(competitor, waitForLatest);
81 67
}
82 68
83 69
@Override
84 70
public void suspend() {
85
- race.getRace().getCourse().lockForRead();
86
- try {
87
- synchronized (this) {
88
- cacheToUse.suspend();
89
- }
90
- } finally {
91
- race.getRace().getCourse().unlockAfterRead();
92
- }
71
+ cacheToUse.suspend();
93 72
}
94 73
95 74
@Override
96 75
public void triggerUpdate(Competitor competitor, EmptyUpdateInterval updateInterval) {
97
- race.getRace().getCourse().lockForRead();
98
- try {
99
- synchronized (this) {
100
- cacheToUse.triggerUpdate(competitor, updateInterval);
101
- }
102
- } finally {
103
- race.getRace().getCourse().unlockAfterRead();
104
- }
76
+ cacheToUse.triggerUpdate(competitor, updateInterval);
105 77
}
106 78
}
... ...
\ No newline at end of file
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverFromSmartFutureCache.java
... ...
@@ -1,68 +0,0 @@
1
-package com.sap.sailing.domain.maneuverhash.impl;
2
-
3
-import java.util.Collections;
4
-import java.util.List;
5
-
6
-import com.sap.sailing.domain.base.CPUMeteringType;
7
-import com.sap.sailing.domain.base.Competitor;
8
-import com.sap.sailing.domain.common.NoWindException;
9
-import com.sap.sailing.domain.maneuverdetection.ManeuverDetector;
10
-import com.sap.sailing.domain.maneuverhash.ManeuverCache;
11
-import com.sap.sailing.domain.tracking.Maneuver;
12
-import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
13
-import com.sap.sse.common.Duration;
14
-import com.sap.sse.util.SmartFutureCache;
15
-import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater;
16
-import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
17
-
18
-public class ManeuverFromSmartFutureCache implements ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> {
19
-
20
- private final SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval> smartFutureCache;
21
-
22
- public ManeuverFromSmartFutureCache(DynamicTrackedRaceImpl race) {
23
- this.smartFutureCache = new SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval>(
24
- new AbstractCacheUpdater<Competitor, List<Maneuver>, EmptyUpdateInterval>() {
25
- @Override
26
- public List<Maneuver> computeCacheUpdate(Competitor competitor, EmptyUpdateInterval updateInterval)
27
- throws NoWindException {
28
- return race.getTrackedRegatta().callWithCPUMeterWithException(()->{
29
- Duration averageIntervalBetweenRawFixes = race.getTrack(competitor).getAverageIntervalBetweenRawFixes();
30
- if (averageIntervalBetweenRawFixes != null) {
31
- ManeuverDetector maneuverDetector;
32
- // 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
33
- // if (averageIntervalBetweenRawFixes.asSeconds() >= 30) {
34
- // maneuverDetector = new LowGPSSamplingRateManeuverDetectorImpl(TrackedRaceImpl.this, competitor);
35
- // } else {
36
- maneuverDetector = race.getManeuverDetectorPerCompetitorCache().getValue(competitor);
37
- // }
38
- List<Maneuver> maneuvers = race.computeManeuvers(competitor, maneuverDetector);
39
- return maneuvers;
40
- } else {
41
- return Collections.emptyList();
42
- }
43
- }, CPUMeteringType.MANEUVER_DETECTION.name());
44
- }
45
- },//.computeCacheUpdate(competitor, null),
46
- /* nameForLocks */ "Maneuver cache for race " + race.getRace().getName());
47
- }
48
-
49
- @Override
50
- public void resume() {
51
- smartFutureCache.resume();
52
- }
53
-
54
- @Override
55
- public List<Maneuver> get(Competitor key, boolean waitForLatest) {
56
- return smartFutureCache.get(key, waitForLatest);
57
- }
58
-
59
- @Override
60
- public void suspend() {
61
- smartFutureCache.suspend();
62
- }
63
-
64
- @Override
65
- public void triggerUpdate(Competitor key, EmptyUpdateInterval updateInterval) {
66
- smartFutureCache.triggerUpdate(key, updateInterval);
67
- }
68
-}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuversFromSmartFutureCache.java
... ...
@@ -0,0 +1,68 @@
1
+package com.sap.sailing.domain.maneuverhash.impl;
2
+
3
+import java.util.Collections;
4
+import java.util.List;
5
+
6
+import com.sap.sailing.domain.base.CPUMeteringType;
7
+import com.sap.sailing.domain.base.Competitor;
8
+import com.sap.sailing.domain.common.NoWindException;
9
+import com.sap.sailing.domain.maneuverdetection.ManeuverDetector;
10
+import com.sap.sailing.domain.maneuverhash.ManeuverCache;
11
+import com.sap.sailing.domain.tracking.Maneuver;
12
+import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
13
+import com.sap.sse.common.Duration;
14
+import com.sap.sse.util.SmartFutureCache;
15
+import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater;
16
+import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
17
+
18
+public class ManeuversFromSmartFutureCache implements ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> {
19
+
20
+ private final SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval> smartFutureCache;
21
+
22
+ public ManeuversFromSmartFutureCache(DynamicTrackedRaceImpl race) {
23
+ this.smartFutureCache = new SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval>(
24
+ new AbstractCacheUpdater<Competitor, List<Maneuver>, EmptyUpdateInterval>() {
25
+ @Override
26
+ public List<Maneuver> computeCacheUpdate(Competitor competitor, EmptyUpdateInterval updateInterval)
27
+ throws NoWindException {
28
+ return race.getTrackedRegatta().callWithCPUMeterWithException(()->{
29
+ Duration averageIntervalBetweenRawFixes = race.getTrack(competitor).getAverageIntervalBetweenRawFixes();
30
+ if (averageIntervalBetweenRawFixes != null) {
31
+ ManeuverDetector maneuverDetector;
32
+ // 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
33
+ // if (averageIntervalBetweenRawFixes.asSeconds() >= 30) {
34
+ // maneuverDetector = new LowGPSSamplingRateManeuverDetectorImpl(TrackedRaceImpl.this, competitor);
35
+ // } else {
36
+ maneuverDetector = race.getManeuverDetectorPerCompetitorCache().getValue(competitor);
37
+ // }
38
+ List<Maneuver> maneuvers = race.computeManeuvers(competitor, maneuverDetector);
39
+ return maneuvers;
40
+ } else {
41
+ return Collections.emptyList();
42
+ }
43
+ }, CPUMeteringType.MANEUVER_DETECTION.name());
44
+ }
45
+ },//.computeCacheUpdate(competitor, null),
46
+ /* nameForLocks */ "Maneuver cache for race " + race.getRace().getName());
47
+ }
48
+
49
+ @Override
50
+ public void resume() {
51
+ smartFutureCache.resume();
52
+ }
53
+
54
+ @Override
55
+ public List<Maneuver> get(Competitor key, boolean waitForLatest) {
56
+ return smartFutureCache.get(key, waitForLatest);
57
+ }
58
+
59
+ @Override
60
+ public void suspend() {
61
+ smartFutureCache.suspend();
62
+ }
63
+
64
+ @Override
65
+ public void triggerUpdate(Competitor key, EmptyUpdateInterval updateInterval) {
66
+ smartFutureCache.triggerUpdate(key, updateInterval);
67
+ }
68
+}