Skip to content

Commit 94a6b0d

Browse files
authored
Merge pull request opentripplanner#7338 from entur/centralize-snapshot-mutations-in-manager
Move snapshot mutations from updaters to TimetableSnapshotManager
2 parents 0cc7699 + bcfeac0 commit 94a6b0d

13 files changed

Lines changed: 665 additions & 310 deletions

File tree

application/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripUpdate.java

Lines changed: 151 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,38 @@
77

88
/**
99
* Represents the real-time update of a single trip.
10-
*
11-
* @param pattern the pattern to which belongs the updated trip. This can be a new
12-
* pattern created in real-time.
13-
* @param updatedTripTimes the new trip times for the updated trip.
14-
* @param serviceDate the service date for which this update applies (updates are valid
15-
* only for one service date)
16-
* @param addedTripOnServiceDate optionally if this trip update adds a new trip, the
17-
* TripOnServiceDate corresponding to this new trip.
18-
* @param tripCreation true if this update creates a new trip, not present in scheduled
19-
* data.
20-
* @param routeCreation true if an added trip cannot be registered under an existing route
21-
* and a new route must be created.
22-
* @param producer the producer of the real-time update.
2310
*/
24-
public record RealTimeTripUpdate(
25-
TripPattern pattern,
26-
TripTimes updatedTripTimes,
27-
LocalDate serviceDate,
28-
@Nullable TripOnServiceDate addedTripOnServiceDate,
29-
boolean tripCreation,
30-
boolean routeCreation,
31-
@Nullable String producer
32-
) {
33-
public RealTimeTripUpdate {
34-
Objects.requireNonNull(pattern);
35-
Objects.requireNonNull(updatedTripTimes);
36-
Objects.requireNonNull(serviceDate);
11+
public final class RealTimeTripUpdate {
12+
13+
private final TripPattern pattern;
14+
private final TripTimes updatedTripTimes;
15+
private final LocalDate serviceDate;
16+
17+
@Nullable
18+
private final TripOnServiceDate addedTripOnServiceDate;
19+
20+
private final boolean tripCreation;
21+
private final boolean routeCreation;
22+
23+
@Nullable
24+
private final String producer;
25+
26+
private final boolean revertPreviousRealTimeUpdates;
27+
28+
@Nullable
29+
private final TripPattern hideTripInScheduledPattern;
30+
31+
private RealTimeTripUpdate(Builder builder) {
32+
this.pattern = Objects.requireNonNull(builder.pattern);
33+
this.updatedTripTimes = Objects.requireNonNull(builder.updatedTripTimes);
34+
this.serviceDate = Objects.requireNonNull(builder.serviceDate);
35+
this.addedTripOnServiceDate = builder.addedTripOnServiceDate;
36+
this.tripCreation = builder.tripCreation;
37+
this.routeCreation = builder.routeCreation;
38+
this.producer = builder.producer;
39+
this.revertPreviousRealTimeUpdates = builder.revertPreviousRealTimeUpdates;
40+
this.hideTripInScheduledPattern = builder.hideTripInScheduledPattern;
41+
3742
if (pattern.numberOfStops() != updatedTripTimes.getNumStops()) {
3843
throw new IllegalArgumentException(
3944
"The pattern %s has %d stops while the TripTimes for Trip %s on service date %s has %d stops".formatted(
@@ -48,32 +53,128 @@ public record RealTimeTripUpdate(
4853
}
4954

5055
/**
51-
* Create a real-time update for an existing trip.
56+
* Create a builder for a real-time trip update.
57+
*
58+
* @param pattern the pattern to which the updated trip belongs. This can be a new
59+
* pattern created in real-time.
60+
* @param updatedTripTimes the new trip times for the updated trip.
61+
* @param serviceDate the service date for which this update applies (updates are valid
62+
* only for one service date).
5263
*/
53-
public RealTimeTripUpdate(
54-
TripPattern pattern,
55-
TripTimes updatedTripTimes,
56-
LocalDate serviceDate
57-
) {
58-
this(pattern, updatedTripTimes, serviceDate, null, false, false, null);
64+
public static Builder of(TripPattern pattern, TripTimes updatedTripTimes, LocalDate serviceDate) {
65+
return new Builder(pattern, updatedTripTimes, serviceDate);
66+
}
67+
68+
public TripPattern pattern() {
69+
return pattern;
70+
}
71+
72+
public TripTimes updatedTripTimes() {
73+
return updatedTripTimes;
74+
}
75+
76+
public LocalDate serviceDate() {
77+
return serviceDate;
78+
}
79+
80+
@Nullable
81+
public TripOnServiceDate addedTripOnServiceDate() {
82+
return addedTripOnServiceDate;
83+
}
84+
85+
public boolean tripCreation() {
86+
return tripCreation;
87+
}
88+
89+
public boolean routeCreation() {
90+
return routeCreation;
91+
}
92+
93+
@Nullable
94+
public String producer() {
95+
return producer;
5996
}
6097

61-
public RealTimeTripUpdate(
62-
TripPattern pattern,
63-
TripTimes updatedTripTimes,
64-
LocalDate serviceDate,
65-
@Nullable TripOnServiceDate addedTripOnServiceDate,
66-
boolean tripCreation,
67-
boolean routeCreation
68-
) {
69-
this(
70-
pattern,
71-
updatedTripTimes,
72-
serviceDate,
73-
addedTripOnServiceDate,
74-
tripCreation,
75-
routeCreation,
76-
null
77-
);
98+
public boolean revertPreviousRealTimeUpdates() {
99+
return revertPreviousRealTimeUpdates;
100+
}
101+
102+
@Nullable
103+
public TripPattern hideTripInScheduledPattern() {
104+
return hideTripInScheduledPattern;
105+
}
106+
107+
public static class Builder {
108+
109+
private final TripPattern pattern;
110+
private final TripTimes updatedTripTimes;
111+
private final LocalDate serviceDate;
112+
private TripOnServiceDate addedTripOnServiceDate = null;
113+
private boolean tripCreation = false;
114+
private boolean routeCreation = false;
115+
private String producer = null;
116+
private boolean revertPreviousRealTimeUpdates = false;
117+
private TripPattern hideTripInScheduledPattern = null;
118+
119+
private Builder(TripPattern pattern, TripTimes updatedTripTimes, LocalDate serviceDate) {
120+
this.pattern = pattern;
121+
this.updatedTripTimes = updatedTripTimes;
122+
this.serviceDate = serviceDate;
123+
}
124+
125+
/**
126+
* Optionally set the TripOnServiceDate for a newly added trip.
127+
*/
128+
public Builder withAddedTripOnServiceDate(TripOnServiceDate addedTripOnServiceDate) {
129+
this.addedTripOnServiceDate = addedTripOnServiceDate;
130+
return this;
131+
}
132+
133+
/**
134+
* Set to true if this update creates a new trip, not present in scheduled data.
135+
*/
136+
public Builder withTripCreation(boolean tripCreation) {
137+
this.tripCreation = tripCreation;
138+
return this;
139+
}
140+
141+
/**
142+
* Set to true if an added trip cannot be registered under an existing route and a new route
143+
* must be created.
144+
*/
145+
public Builder withRouteCreation(boolean routeCreation) {
146+
this.routeCreation = routeCreation;
147+
return this;
148+
}
149+
150+
/**
151+
* Set the producer of the real-time update.
152+
*/
153+
public Builder withProducer(String producer) {
154+
this.producer = producer;
155+
return this;
156+
}
157+
158+
/**
159+
* Signals the snapshot manager to revert any previous pattern modifications for this trip
160+
* before applying the update.
161+
*/
162+
public Builder withRevertPreviousRealTimeUpdates(boolean revertPreviousRealTimeUpdates) {
163+
this.revertPreviousRealTimeUpdates = revertPreviousRealTimeUpdates;
164+
return this;
165+
}
166+
167+
/**
168+
* When non-null, signals the snapshot manager to mark the trip as deleted in this pattern
169+
* (prevents duplication when moving to a modified pattern).
170+
*/
171+
public Builder withHideTripInScheduledPattern(TripPattern hideTripInScheduledPattern) {
172+
this.hideTripInScheduledPattern = hideTripInScheduledPattern;
173+
return this;
174+
}
175+
176+
public RealTimeTripUpdate build() {
177+
return new RealTimeTripUpdate(this);
178+
}
78179
}
79180
}

application/src/main/java/org/opentripplanner/updater/trip/TimetableSnapshotManager.java

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@
1515
import org.opentripplanner.updater.TimetableSnapshotParameters;
1616
import org.opentripplanner.updater.spi.UpdateError;
1717
import org.opentripplanner.updater.spi.UpdateSuccess;
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
1820

1921
/**
2022
* A class which abstracts away locking, updating, committing and purging of the timetable snapshot.
2123
*/
2224
public final class TimetableSnapshotManager {
2325

26+
private static final Logger LOG = LoggerFactory.getLogger(TimetableSnapshotManager.class);
27+
2428
private final RealTimeRaptorTransitDataUpdater realtimeRaptorTransitDataUpdater;
2529

2630
/**
@@ -126,18 +130,6 @@ public void purgeAndCommit() {
126130
}
127131
}
128132

129-
/**
130-
* If a previous realtime update has changed which trip pattern is associated with the given trip
131-
* on the given service date, this method will dissociate the trip from that pattern and remove
132-
* the trip's timetables from that pattern on that particular service date.
133-
* <p>
134-
* For this service date, the trip will revert to its original trip pattern from the scheduled
135-
* data, remaining on that pattern unless it's changed again by a future realtime update.
136-
*/
137-
public void revertTripToScheduledTripPattern(FeedScopedId tripId, LocalDate serviceDate) {
138-
buffer.revertTripToScheduledTripPattern(tripId, serviceDate);
139-
}
140-
141133
/**
142134
* Remove realtime data from previous service dates from the snapshot. This is useful so that
143135
* instances that run for multiple days don't accumulate a lot of realtime data for past
@@ -179,8 +171,35 @@ public void clearBuffer(String feedId) {
179171
* @return whether the update was actually applied
180172
*/
181173
public Result<UpdateSuccess, UpdateError> updateBuffer(RealTimeTripUpdate realTimeTripUpdate) {
174+
var trip = realTimeTripUpdate.updatedTripTimes().getTrip();
175+
var serviceDate = realTimeTripUpdate.serviceDate();
176+
177+
// Phase 1: Revert previous real-time modifications if requested
178+
if (realTimeTripUpdate.revertPreviousRealTimeUpdates()) {
179+
buffer.revertTripToScheduledTripPattern(trip.getId(), serviceDate);
180+
}
181+
182+
// Phase 2: Mark trip as deleted in scheduled pattern if moving to a modified pattern
183+
var scheduledPattern = realTimeTripUpdate.hideTripInScheduledPattern();
184+
if (scheduledPattern != null) {
185+
var scheduledTripTimes = scheduledPattern.getScheduledTimetable().getTripTimes(trip);
186+
if (scheduledTripTimes != null) {
187+
var builder = scheduledTripTimes.createRealTimeFromScheduledTimes();
188+
builder.deleteTrip();
189+
buffer.update(
190+
RealTimeTripUpdate.of(scheduledPattern, builder.build(), serviceDate).build()
191+
);
192+
} else if (LOG.isDebugEnabled()) {
193+
LOG.debug(
194+
"Trip {} not found in scheduled pattern {}, skipping deletion.",
195+
trip.getId(),
196+
scheduledPattern.logName()
197+
);
198+
}
199+
}
200+
201+
// Phase 3: Apply the main update
182202
buffer.update(realTimeTripUpdate);
183-
// The time tables are finished during the commit
184203
return Result.success(UpdateSuccess.noWarnings(realTimeTripUpdate.producer()));
185204
}
186205

0 commit comments

Comments
 (0)