mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-03 09:39:38 +00:00
Closes a replica-bootstrap ordering hazard uncovered by working through the replication path in detail: On a replica, RacingEventServiceImpl.initiallyFillFromInternal deserializes each DynamicTrackedRegatta with its trackedRaces map already populated (the map is non-transient in TrackedRegattaImpl), so no raceAdded events fire during deserialization itself. What fires raceAdded on the replica is the subsequent ensureRegattaHasRaceAdditionListener call, which invokes TrackedRegatta.addRaceListener(...) -- and that method synchronously replays raceAdded(...) for every pre-existing tracked race (see the addRaceListener body in TrackedRegattaImpl and its Javadoc: 'firing events for the already existing TrackedRace instances when adding a new listener'). At that moment, both polarDataService and windEstimationFactoryService in the replica's RacingEventServiceImpl may still be null (their OSGi trackers have not fired yet -- their arrival order is undetermined). Two scenarios need handling: * Polar service arrives first, factory second: raceAdded skipped the scheduleWindEstimationInstallation call because the factory was null; setWindEstimationFactoryService then iterates all races and schedules installs, which observe a non-null polar service and proceed as intended. This case already worked. * Factory arrives first, polar service second: raceAdded skipped the trackedRace.setPolarDataService call because the polar service was null; setWindEstimationFactoryService then schedules an install per race. The install's runWhenPastLoading callback fires immediately because replicated races typically arrive already past LOADING; it sees polarDataService == null and silently drops out, never registering a runWhenPolarLoadingFinishedFor callback. Then setPolarDataService iterates via setPolarDataServiceOnAllTrackedRaces and attaches the polar service to each race -- but nothing was retriggering the wind-estimation install. This case was BROKEN. Fix: in setPolarDataServiceOnAllTrackedRaces, capture the wind factory at method entry and, if it's already available when the polar service arrives, reschedule the install per race. scheduleWindEstimationInstallation is idempotent and guarded against duplicate installation, so this is a safe no-op for races that already got their estimator through another code path. Notes on the broader replication picture (informing this fix): * TrackedRaceImpl.polarDataService and .windEstimation are both transient; after deserialization on the replica they are null and must be set explicitly by the RaceAdditionListener path. * PolarDataService has no PolarDataOperation implementations and PolarDataServiceImpl never calls replicate(...); the primary's polar model state is shipped once via serializeForInitialReplicationInternal / initiallyFillFromInternal (which replaces the polarDataMiner wholesale on the replica), and after that the replica re-mines independently from fixes fed through its own PolarFixCacheUpdater (installed by raceAdded). * TrackedRaceReplicatorAndNotifier.windDataReceived explicitly filters out WindSourceType.MANEUVER_BASED_ESTIMATION when replicating wind fixes (see the existing check), so replicas run their own estimator locally and produce their own fixes -- which makes correct estimator installation on the replica just as important as on the primary.