[traffxml] Purge expired messages

Signed-off-by: mvglasow <michael -at- vonglasow.com>
This commit is contained in:
mvglasow
2025-06-15 16:40:03 +03:00
parent db3ed87b92
commit f31541efb2
6 changed files with 86 additions and 5 deletions

View File

@@ -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<std::mutex> 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<std::mutex> 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())

View File

@@ -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.
*

View File

@@ -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();

View File

@@ -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.
*/

View File

@@ -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<TrafficImpact> TraffMessage::GetTrafficImpact()
{
// no events, no impact

View File

@@ -359,6 +359,27 @@ using MultiMwmColoring = std::map<MwmSet::MwmId, std::map<traffic::TrafficInfo::
struct TraffMessage
{
/**
* @brief Gets the time after which this message effectively expires.
*
* The effective expiration time is the latest of `m_expirationTime`, `m_startTime` and
* `m_endTime`. `nullopt` values are ignored.
*
* @return The effective expiration time for the message.
*/
IsoTime GetEffectiveExpirationTime();
/**
* @brief Whether the message has expired.
*
* A message is considered to have expired if its effective expiration time (as returned by
* `GetEffectiveExpirationTime()` refers to a point in time before `now`.
*
* @param now The reference time to compare to (usually current time)
* @return True if the message has expired, false if not.
*/
bool IsExpired(IsoTime now);
/**
* @brief Retrieves the traffic impact of all events.
*