1fbb51ee3bda50730a932ada6768a594b476d322
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 | +} |