From f31541efb2ea7e9e36f5846bb7764e45ac5c9381 Mon Sep 17 00:00:00 2001 From: mvglasow Date: Sun, 15 Jun 2025 16:40:03 +0300 Subject: [PATCH] [traffxml] Purge expired messages Signed-off-by: mvglasow --- map/traffic_manager.cpp | 34 ++++++++++++++++--- map/traffic_manager.hpp | 10 +++++- traffxml/traff_assessment_tool/mainwindow.cpp | 6 ++++ traffxml/traff_assessment_tool/mainwindow.hpp | 5 +++ traffxml/traff_model.cpp | 15 ++++++++ traffxml/traff_model.hpp | 21 ++++++++++++ 6 files changed, 86 insertions(+), 5 deletions(-) diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp index 9b0f8a6fb..a3d3dfb5c 100644 --- a/map/traffic_manager.cpp +++ b/map/traffic_manager.cpp @@ -22,6 +22,12 @@ namespace * Poll interval for traffic data */ auto constexpr kUpdateInterval = minutes(1); + +/** + * Purge interval for expired traffic messages + */ +auto constexpr kPurgeInterval = minutes(1); + auto constexpr kOutdatedDataTimeout = minutes(5) + kUpdateInterval; auto constexpr kNetworkErrorTimeout = minutes(20); @@ -404,6 +410,21 @@ void TrafficManager::Push(traffxml::TraffFeed feed) m_condition.notify_one(); } +void TrafficManager::PurgeExpiredMessages() +{ + std::lock_guard lock(m_mutex); + LOG(LINFO, ("before:", m_messageCache.size(), "message(s)")); + traffxml::IsoTime now = traffxml::IsoTime::Now(); + for (auto it = m_messageCache.begin(); it != m_messageCache.end(); ) + { + if (it->second.IsExpired(now)) + it = m_messageCache.erase(it); + else + ++it; + } + LOG(LINFO, ("after:", m_messageCache.size(), "message(s)")); +} + void TrafficManager::ConsolidateFeedQueue() { std::lock_guard lock(m_mutex); @@ -504,7 +525,8 @@ void TrafficManager::DecodeFirstMessage() void TrafficManager::ThreadRoutine() { - // initially, treat drape and observer as having just been updated + // initially, treat last purge and drape/observer update as having just happened + auto lastPurged = steady_clock::now(); m_lastDrapeUpdate = steady_clock::now(); m_lastObserverUpdate = steady_clock::now(); @@ -513,11 +535,15 @@ void TrafficManager::ThreadRoutine() if (!IsEnabled()) continue; - // TODO clean out expired messages - if (!IsTestMode()) { - LOG(LINFO, ("start loop, active MWMs changed:", m_activeMwmsChanged, ", poll needed:", m_isPollNeeded)); + if (steady_clock::now() - lastPurged >= kPurgeInterval) + { + lastPurged == steady_clock::now(); + PurgeExpiredMessages(); + } + + LOG(LINFO, ("active MWMs changed:", m_activeMwmsChanged, ", poll needed:", m_isPollNeeded)); // this is a no-op if active MWMs have not changed if (!SetSubscriptionArea()) diff --git a/map/traffic_manager.hpp b/map/traffic_manager.hpp index 1ba78b605..6ffc19b56 100644 --- a/map/traffic_manager.hpp +++ b/map/traffic_manager.hpp @@ -198,7 +198,8 @@ public: * will log a warning but otherwise do nothing. * * In test mode, the traffic manager will not subscribe to sources or poll them automatically. - * It will still receive and process push feeds. + * Expired messages will not get purged automatically, but `PurgeExpiredMessages()` can be called + * to purge expired messages once. The traffic manager will still receive and process push feeds. * * Future versions may introduce further behavior changes. */ @@ -215,6 +216,13 @@ public: */ void Push(traffxml::TraffFeed feed); + /** + * @brief Purges expired messages from the cache. + * + * This method is safe to call from any thread. + */ + void PurgeExpiredMessages(); + /** * @brief Clears the entire traffic cache. * diff --git a/traffxml/traff_assessment_tool/mainwindow.cpp b/traffxml/traff_assessment_tool/mainwindow.cpp index 2a7a8d815..0313c663f 100644 --- a/traffxml/traff_assessment_tool/mainwindow.cpp +++ b/traffxml/traff_assessment_tool/mainwindow.cpp @@ -265,6 +265,7 @@ MainWindow::MainWindow(Framework & framework) menuBar()->addMenu(fileMenu); fileMenu->addAction("Open sample", QKeySequence("Ctrl+O"), this, &MainWindow::OnOpenTrafficSample); + fileMenu->addAction("Purge expired messages", QKeySequence("Ctrl+P"), this, &MainWindow::OnPurgeExpiredMessages); fileMenu->addAction("Clear TraFF cache", QKeySequence("Ctrl+D"), this, &MainWindow::OnClearCache); m_closeTrafficSampleAction = fileMenu->addAction("Close sample", QKeySequence("Ctrl+W"), this, &MainWindow::OnCloseTrafficSample); @@ -408,6 +409,11 @@ void MainWindow::OnOpenTrafficSample() #endif } +void MainWindow::OnPurgeExpiredMessages() +{ + m_framework.GetTrafficManager().PurgeExpiredMessages(); +} + void MainWindow::OnClearCache() { m_framework.GetTrafficManager().Clear(); diff --git a/traffxml/traff_assessment_tool/mainwindow.hpp b/traffxml/traff_assessment_tool/mainwindow.hpp index e0b9a9058..02fa4803f 100644 --- a/traffxml/traff_assessment_tool/mainwindow.hpp +++ b/traffxml/traff_assessment_tool/mainwindow.hpp @@ -41,6 +41,11 @@ private: */ void OnOpenTrafficSample(); + /** + * Called when the user requests to purge expired messages. + */ + void OnPurgeExpiredMessages(); + /** * Called when the user requests to clear the cache. */ diff --git a/traffxml/traff_model.cpp b/traffxml/traff_model.cpp index 544ed73e0..54cf18943 100644 --- a/traffxml/traff_model.cpp +++ b/traffxml/traff_model.cpp @@ -195,6 +195,21 @@ bool operator==(TraffLocation const & lhs, TraffLocation const & rhs) && (lhs.m_to == rhs.m_to); } +IsoTime TraffMessage::GetEffectiveExpirationTime() +{ + IsoTime result = m_expirationTime; + if (m_startTime && m_startTime.value() > result) + result = m_startTime.value(); + if (m_endTime && m_endTime.value() > result) + result = m_endTime.value(); + return result; +} + +bool TraffMessage::IsExpired(IsoTime now) +{ + return GetEffectiveExpirationTime() < now; +} + std::optional TraffMessage::GetTrafficImpact() { // no events, no impact diff --git a/traffxml/traff_model.hpp b/traffxml/traff_model.hpp index 26512b81e..05f5d7675 100644 --- a/traffxml/traff_model.hpp +++ b/traffxml/traff_model.hpp @@ -359,6 +359,27 @@ using MultiMwmColoring = std::map