>>();
@@ -480,6 +484,25 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
triggerManeuverCacheRecalculationForAllCompetitors();
logger.info("Deserialized race " + getRace().getName());
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
+ // considering the unlikely possibility that the course and this tracked race's internal structures
+ // may be inconsistent, e.g., due to non-atomic serialization of course and tracked race; see bug 2223
+ adjustStructureToCourse();
+ }
+
+ /**
+ * When the {@link TrackedRace} object and the {@link RaceDefinition} and in particular its {@link CourseImpl} objects are not
+ * atomically serialized, inconsistencies may occur during de-serialization. In particular, the tracked race's leg-oriented
+ * structures may not consistently reflect the course's leg sequence because a course update could have happened between
+ * course serialization and tracked race serialization.
+ *
+ * To fix this, the list of waypoints as found in this tracked race's leg-oriented structures, compared to the course's
+ * waypoint list, produces a patch that can be applied to this tracked race, resulting in the necessary
+ * {@link #waypointAdded(int, Waypoint)} and {@link #waypointRemoved(int, Waypoint)} calls.
+ */
+ private void adjustStructureToCourse() throws PatchFailedException {
+ final TrackedRaceAsWaypointList trackedRaceAsWaypointList = new TrackedRaceAsWaypointList(this);
+ Patch diff = DiffUtils.diff(getRace().getCourse().getWaypoints(), trackedRaceAsWaypointList);
+ diff.applyTo(trackedRaceAsWaypointList);
}
@Override