0404e1bd63d477832c23490490559158dbdb761b
java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogDeviceMappings.java
| ... | ... | @@ -92,6 +92,14 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> { |
| 92 | 92 | */ |
| 93 | 93 | private final Map<DeviceIdentifier, Pair<TimeRange, List<DeviceMappingWithRegattaLogEvent<ItemT>>>> cachedMappings = new HashMap<>(); |
| 94 | 94 | |
| 95 | + /** |
|
| 96 | + * When the {@link #cachedMappings} are to be updated, the corresponding update job is stored in this field. It must be executed |
|
| 97 | + * under the {@link #mappingsLock}'s write lock. However, when other updates to {@link #mappings} or {@link #mappingsByDevice} |
|
| 98 | + * are performed (usually by the {@link #updateMappingsInternal()} method), this field will be cleared because the cache update |
|
| 99 | + * will most likely be obsolete. |
|
| 100 | + */ |
|
| 101 | + private Runnable cacheUpdateJob; |
|
| 102 | + |
|
| 95 | 103 | private int cacheHits; |
| 96 | 104 | private int cacheMisses; |
| 97 | 105 | |
| ... | ... | @@ -182,7 +190,13 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> { |
| 182 | 190 | |
| 183 | 191 | /** |
| 184 | 192 | * Calls the given callback for every DeviceMapping that is known for the given {@link DeviceIdentifier} that |
| 185 | - * includes the given {@link TimePoint}. |
|
| 193 | + * includes the given {@link TimePoint}.<p> |
|
| 194 | + * |
|
| 195 | + * Searches the {@link #cachedMappings} for a match for the {@code device}; if found, checks whether {@code timePoint} |
|
| 196 | + * is within the time range for which device mappings were cached, and if so, uses those device mappings. Otherwise, |
|
| 197 | + * the device mappings are calculated and a cache update is carried out after releasing the read-lock of |
|
| 198 | + * {@link #mappingsLock} and after obtaining its write-lock. Should an update have been squeezed in between releasing |
|
| 199 | + * the read-lock and obtaining the write-lock, the cache update is not carried out. |
|
| 186 | 200 | * |
| 187 | 201 | * @param device |
| 188 | 202 | * the device to get the mappings for |
| ... | ... | @@ -204,15 +218,14 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> { |
| 204 | 218 | cachedTimeRangeForDevice.getB().forEach(mapping->callback.accept(mapping)); |
| 205 | 219 | } else { |
| 206 | 220 | final List<DeviceMappingWithRegattaLogEvent<ItemT>> mappingsForDevice = mappingsByDevice.get(device); |
| 207 | - MultiTimeRange timeRangeForCache = MultiTimeRange.of(); |
|
| 221 | + TimeRange timeRangeForCache = null; |
|
| 208 | 222 | final List<DeviceMappingWithRegattaLogEvent<ItemT>> deviceMappingsForCache = new LinkedList<>(); |
| 209 | - assert timeRangeForCache.isEmpty(); |
|
| 210 | 223 | cacheMisses++; |
| 211 | 224 | if (mappingsForDevice != null) { |
| 212 | 225 | for (final DeviceMappingWithRegattaLogEvent<ItemT> mapping : mappingsForDevice) { |
| 213 | 226 | if (mapping.getTimeRange().includes(timePoint)) { |
| 214 | - if (timeRangeForCache.isEmpty()) { |
|
| 215 | - timeRangeForCache.union(mapping.getTimeRange()); |
|
| 227 | + if (timeRangeForCache == null) { |
|
| 228 | + timeRangeForCache = mapping.getTimeRange(); |
|
| 216 | 229 | } else { |
| 217 | 230 | timeRangeForCache = timeRangeForCache.intersection(mapping.getTimeRange()); |
| 218 | 231 | } |
| ... | ... | @@ -221,12 +234,20 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> { |
| 221 | 234 | } |
| 222 | 235 | } |
| 223 | 236 | } |
| 224 | - final MultiTimeRange finalTimeRangeForache = timeRangeForCache; |
|
| 237 | + final TimeRange finalTimeRangeForCache = timeRangeForCache; |
|
| 225 | 238 | logger.fine(() -> "Device mapping cache miss for mapper " + this + " for device " + device |
| 226 | 239 | + " and time point " + timePoint + ", determined cachable range " |
| 227 | - + finalTimeRangeForache + "; " + cacheHits + " hits, " + cacheMisses + " misses"); |
|
| 228 | - |
|
| 229 | - // TODO bug6236 Now issue the caching of the entry (device, (timeRangeForCache, deviceMappingsForCache)) under the mappingsLock's write lock! |
|
| 240 | + + finalTimeRangeForCache + "; " + cacheHits + " hits, " + cacheMisses + " misses"); |
|
| 241 | + cacheUpdateJob = ()->cachedMappings.put(device, new Pair<>(finalTimeRangeForCache, deviceMappingsForCache)); |
|
| 242 | + } |
|
| 243 | + }); |
|
| 244 | + LockUtil.executeWithWriteLock(mappingsLock, ()->{ |
|
| 245 | + if (cacheUpdateJob != null) { |
|
| 246 | + logger.fine(()-> "Device mapping cache miss for mapper " + this + " performs cache update."); |
|
| 247 | + cacheUpdateJob.run(); |
|
| 248 | + } else { |
|
| 249 | + logger.fine(() -> "Device mapping cache miss for mapper " + this |
|
| 250 | + + " does not update the cache because the mappings were updated in between"); |
|
| 230 | 251 | } |
| 231 | 252 | }); |
| 232 | 253 | } |
| ... | ... | @@ -299,6 +320,7 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> { |
| 299 | 320 | cachedMappings.clear(); |
| 300 | 321 | mappings.putAll(newMappings); |
| 301 | 322 | mappingsByDevice.clear(); |
| 323 | + cacheUpdateJob = null; |
|
| 302 | 324 | for (ItemT item : newMappings.keySet()) { |
| 303 | 325 | for (DeviceMappingWithRegattaLogEvent<ItemT> mapping : newMappings.get(item)) { |
| 304 | 326 | List<DeviceMappingWithRegattaLogEvent<ItemT>> list = mappingsByDevice.get(mapping.getDevice()); |
java/target/configuration/logging_debug.properties
| ... | ... | @@ -68,4 +68,7 @@ com.sap.sse.landscape.impl.GithubReleasesRepository.level = FINE |
| 68 | 68 | |
| 69 | 69 | # Produce wind-from-maneuver estimation graph: |
| 70 | 70 | #com.sap.sailing.windestimation.integration.IncrementalMstHmmWindEstimationForTrackedRaceTest.level = FINE |
| 71 | -#com.sap.sailing.windestimation.integration.IncrementalMstHmmWindEstimationForTrackedRace.level = FINE |
|
| ... | ... | \ No newline at end of file |
| 0 | +#com.sap.sailing.windestimation.integration.IncrementalMstHmmWindEstimationForTrackedRace.level = FINE |
|
| 1 | + |
|
| 2 | +# Log device mapping caching |
|
| 3 | +com.sap.sailing.domain.racelogtracking.impl.fixtracker.RegattaLogDeviceMappings.level = FINE |