diff --git a/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java b/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java index 53664c097..5a1e8f062 100644 --- a/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java +++ b/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java @@ -236,6 +236,16 @@ public void makeVehicleUnpredictableAndGrabAssignment( vehicleState.unsetBlock(BlockAssignmentMethod.ASSIGNMENT_GRABBED); } + /** + * Removes the vehicle from the VehicleDataCache. + * + * @param vehicleId + * The vehicle to remove + */ + public void removeFromVehicleDataCache(String vehicleId) { + VehicleDataCache.getInstance().removeVehicle(vehicleId); + } + /** * Looks at the previous AVL reports to determine if vehicle is actually * moving. If it is not moving then the vehicle is made unpredictable. Uses @@ -1320,7 +1330,7 @@ private void determineAndSetRealTimeSchAdh(VehicleState vehicleState) { // Determine the schedule adherence for the vehicle TemporalDifference scheduleAdherence = RealTimeSchedAdhProcessor .generate(vehicleState); - + // Store the schedule adherence with the vehicle vehicleState.setRealTimeSchedAdh(scheduleAdherence); } diff --git a/transitclock/src/main/java/org/transitclock/core/TimeoutHandlerModule.java b/transitclock/src/main/java/org/transitclock/core/TimeoutHandlerModule.java index 68f2bddfa..6407628b1 100644 --- a/transitclock/src/main/java/org/transitclock/core/TimeoutHandlerModule.java +++ b/transitclock/src/main/java/org/transitclock/core/TimeoutHandlerModule.java @@ -22,6 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.transitclock.applications.Core; +import org.transitclock.config.BooleanConfigValue; import org.transitclock.config.IntegerConfigValue; import org.transitclock.configData.AgencyConfig; import org.transitclock.core.dataCache.VehicleStateManager; @@ -87,6 +88,18 @@ public class TimeoutHandlerModule extends Module { + "for long after scheduled departure time if vehicle " + "taken out of service."); + private static BooleanConfigValue removeTimedOutVehiclesFromVehicleDataCache = + new BooleanConfigValue( + "transitclock.timeout.removeTimedOutVehiclesFromVehicleDataCache", + false, + "When timing out vehicles, the default behavior is to make " + + "the vehicle unpredictable but leave it in the " + + "VehicleDataCache. When set to true, a timeout will also " + + "remove the vehicle from the VehicleDataCache. This can " + + "be useful in situations where it is not desirable to " + + "include timed out vehicles in data feeds, e.g. the GTFS " + + "Realtime vehicle positions feed."); + /********************* Logging ************************************/ private static final Logger logger = LoggerFactory @@ -115,6 +128,19 @@ public void storeAvlReport(AvlReport avlReport) { avlReportsMap.put(avlReport.getVehicleId(), avlReport); } } + + /** + * Removes the specified vehicle from the VehicleDataCache if configured to do so + * + * @param vehicleId + * Vehicle to remove + */ + public void removeFromVehicleDataCache(String vehicleId) { + if (removeTimedOutVehiclesFromVehicleDataCache.getValue()) { + logger.info("Removing vehicleId={} from VehicleDataCache", vehicleId); + AvlProcessor.getInstance().removeFromVehicleDataCache(vehicleId); + } + } /** * For regular predictable vehicle that is not a schedule based prediction @@ -147,20 +173,43 @@ private void handlePredictablePossibleTimeout(VehicleState vehicleState, long no // Remove vehicle from map for next time looking for timeouts mapIterator.remove(); - + + // Remove vehicle from cache if configured to do so + removeFromVehicleDataCache(vehicleState.getVehicleId()); } } /** - * Don't need to worry about vehicles that are not predictable. But might as - * well remove vehicle from map so don't examine vehicle every - * TimeoutHandleModule polling cycle + * For not predictable vehicle. If not removing vehicles from cache, + * removes the vehicle from the map to avoid looking at it again. If + * configured to remove timed out vehicles from cache, and haven't + * reported in too long, removes the vehicle from map and cache. * * @param mapIterator * So can remove AVL report from map */ - private void handleNotPredictablePossibleTimeout(Iterator mapIterator) { - mapIterator.remove(); + private void handleNotPredictablePossibleTimeout(VehicleState vehicleState, + long now, Iterator mapIterator) { + if (!removeTimedOutVehiclesFromVehicleDataCache.getValue()) { + // Remove vehicle from map for next time looking for timeouts and return + mapIterator.remove(); + return; + } + + // If haven't reported in too long... + long maxNoAvl = allowableNoAvlSecs.getValue() * Time.MS_PER_SEC; + if (now > vehicleState.getAvlReport().getTime() + maxNoAvl) { + + // Log the situation + logger.info("For not predictable vehicleId={} generated timeout " + + "event.", vehicleState.getVehicleId()); + + // Remove vehicle from map for next time looking for timeouts + mapIterator.remove(); + + // Remove vehicle from cache + removeFromVehicleDataCache(vehicleState.getVehicleId()); + } } /** @@ -190,7 +239,10 @@ private void handleSchedBasedPredsPossibleTimeout(VehicleState vehicleState, vehicleState.getVehicleId(), shouldTimeoutEventDescription); // Remove vehicle from map for next time looking for timeouts - mapIterator.remove(); + mapIterator.remove(); + + // Remove vehicle from cache if configured to do so + removeFromVehicleDataCache(vehicleState.getVehicleId()); } } @@ -263,6 +315,9 @@ private void handleWaitStopPossibleTimeout(VehicleState vehicleState, long now, // Remove vehicle from map for next time looking for timeouts mapIterator.remove(); + + // Remove vehicle from cache if configured to do so + removeFromVehicleDataCache(vehicleState.getVehicleId()); } } } @@ -294,7 +349,8 @@ public void handlePossibleTimeouts() { synchronized (vehicleState) { if (!vehicleState.isPredictable()) { // Vehicle is not predictable - handleNotPredictablePossibleTimeout(mapIterator); + handleNotPredictablePossibleTimeout(vehicleState, now, + mapIterator); } else if (vehicleState.isForSchedBasedPreds()) { // Handle schedule based predictions vehicle handleSchedBasedPredsPossibleTimeout(vehicleState, now, diff --git a/transitclock/src/main/java/org/transitclock/core/dataCache/VehicleDataCache.java b/transitclock/src/main/java/org/transitclock/core/dataCache/VehicleDataCache.java index e0797b0e9..82814700f 100644 --- a/transitclock/src/main/java/org/transitclock/core/dataCache/VehicleDataCache.java +++ b/transitclock/src/main/java/org/transitclock/core/dataCache/VehicleDataCache.java @@ -539,4 +539,15 @@ public void updateVehicle(VehicleState vehicleState) { updateVehicleIdsByBlockMap(originalVehicle, vehicle); updateVehiclesMap(vehicle); } + + /** + * Removes a vehicle from the vehiclesMap + * + * @param vehicleId + * The id of the vehicle to remove from the vehiclesMap + */ + public void removeVehicle(String vehicleId) { + logger.debug("Removing from VehicleDataCache vehiclesMap vehicleId={}", vehicleId); + vehiclesMap.remove(vehicleId); + } }