From 488159e2f94febf1ecf89d4266b3c054198bbea3 Mon Sep 17 00:00:00 2001 From: mvglasow Date: Sat, 7 Jun 2025 14:41:24 +0300 Subject: [PATCH] [traffic] Implement Clear() Signed-off-by: mvglasow --- map/traffic_manager.cpp | 116 +++++++++++++++++++++++++++++----------- map/traffic_manager.hpp | 54 +++++++++++-------- 2 files changed, 117 insertions(+), 53 deletions(-) diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp index d701f5831..049e0644a 100644 --- a/map/traffic_manager.cpp +++ b/map/traffic_manager.cpp @@ -136,17 +136,38 @@ void TrafficManager::SetEnabled(bool enabled) void TrafficManager::Clear() { -// TODO no longer needed + { + std::lock_guard lock(m_mutex); + + LOG(LINFO, ("Messages in cache:", m_messageCache.size())); + LOG(LINFO, ("Feeds in queue:", m_feedQueue.size())); + LOG(LINFO, ("MWMs with coloring:", m_allMwmColoring.size())); + LOG(LINFO, ("MWM cache size:", m_mwmCache.size())); + LOG(LINFO, ("Clearing...")); + // TODO no longer needed #ifdef traffic_dead_code - m_currentCacheSizeBytes = 0; + m_currentCacheSizeBytes = 0; #endif - m_mwmCache.clear(); - m_lastDrapeMwmsByRect.clear(); - m_lastRoutingMwmsByRect.clear(); - m_activeDrapeMwms.clear(); - m_activeRoutingMwms.clear(); - m_requestedMwms.clear(); - m_trafficETags.clear(); + m_messageCache.clear(); + m_feedQueue.clear(); + m_allMwmColoring.clear(); + m_mwmCache.clear(); + + // TODO figure out which of the ones below we still need + m_lastDrapeMwmsByRect.clear(); + m_lastRoutingMwmsByRect.clear(); + // TODO clearing these breaks ForEachActiveMwm, can we leave them? + //m_activeDrapeMwms.clear(); + //m_activeRoutingMwms.clear(); + m_requestedMwms.clear(); + m_trafficETags.clear(); + + LOG(LINFO, ("Messages in cache:", m_messageCache.size())); + LOG(LINFO, ("Feeds in queue:", m_feedQueue.size())); + LOG(LINFO, ("MWMs with coloring:", m_allMwmColoring.size())); + LOG(LINFO, ("MWM cache size:", m_mwmCache.size())); + } + OnTrafficDataUpdate(); } void TrafficManager::SetDrapeEngine(ref_ptr engine) @@ -450,21 +471,29 @@ void TrafficManager::DecodeFirstMessage() m_feedQueue.erase(m_feedQueue.begin()); } - // check if message is actually newer - auto it = m_messageCache.find(message.m_id); - bool process = (it == m_messageCache.end()); - if (!process) - process = (it->second.m_updateTime < message.m_updateTime); - if (!process) { - LOG(LINFO, ("message", message.m_id, "is already in cache, skipping")); - return; + std::lock_guard lock(m_mutex); + + // check if message is actually newer + auto it = m_messageCache.find(message.m_id); + bool process = (it == m_messageCache.end()); + if (!process) + process = (it->second.m_updateTime < message.m_updateTime); + if (!process) + { + LOG(LINFO, ("message", message.m_id, "is already in cache, skipping")); + return; + } } LOG(LINFO, (" ", message.m_id, ":", message)); m_traffDecoder->DecodeMessage(message); - // store message in cache - m_messageCache.insert_or_assign(message.m_id, message); + { + std::lock_guard lock(m_mutex); + + // store message in cache + m_messageCache.insert_or_assign(message.m_id, message); + } // store message coloring in AllMwmColoring // TODO trigger full cache processing if segments were removed or traffic has eased traffxml::MergeMultiMwmColoring(message.m_decoded, m_allMwmColoring); @@ -518,7 +547,9 @@ void TrafficManager::ThreadRoutine() DecodeFirstMessage(); // set new coloring for MWMs - OnTrafficDataUpdate(m_allMwmColoring); + // `m_mutex` is obtained inside the method, no need to do it here + // TODO drop the argument, use class member inside method + OnTrafficDataUpdate(); // TODO no longer needed #ifdef traffic_dead_code @@ -688,15 +719,21 @@ void TrafficManager::OnTrafficRequestFailed(traffic::TrafficInfo && info) } #endif -void TrafficManager::OnTrafficDataUpdate(std::map & trafficCache) +void TrafficManager::OnTrafficDataUpdate() { + bool feedQueueEmpty = false; + + { + std::lock_guard lock(m_mutex); + feedQueueEmpty = m_feedQueue.empty(); + } // Whether to notify the Drape engine of the update. - bool notifyDrape = (m_feedQueue.empty()); + bool notifyDrape = (feedQueueEmpty); // Whether to notify the observer of the update. - bool notifyObserver = (m_feedQueue.empty()); + bool notifyObserver = (feedQueueEmpty); - if (!m_feedQueue.empty()) + if (!feedQueueEmpty) { auto const currentTime = steady_clock::now(); auto const drapeAge = currentTime - m_lastDrapeUpdate; @@ -720,13 +757,14 @@ void TrafficManager::OnTrafficDataUpdate(std::map lock(m_mutex); + // TODO do this for each MWM, active or not + ForEachActiveMwm([this, notifyDrape, notifyObserver](MwmSet::MwmId const & mwmId) { + std::lock_guard lock(m_mutex); + ASSERT(mwmId.IsAlive(), ()); + auto tcit = m_allMwmColoring.find(mwmId); + if (tcit != m_allMwmColoring.end()) + { traffic::TrafficInfo::Coloring coloring = tcit->second; LOG(LINFO, ("Setting new coloring for", mwmId, "with", coloring.size(), "entries")); traffic::TrafficInfo info(mwmId, std::move(coloring)); @@ -758,6 +796,24 @@ void TrafficManager::OnTrafficDataUpdate(std::map(mwmId)); + m_lastDrapeUpdate = steady_clock::now(); + } + + if (notifyObserver) + { + // Update traffic colors for routing. + m_observer.OnTrafficInfoRemoved(mwmId); + m_lastObserverUpdate = steady_clock::now(); + } + } }); } diff --git a/map/traffic_manager.hpp b/map/traffic_manager.hpp index 97c7f0196..c47a1723a 100644 --- a/map/traffic_manager.hpp +++ b/map/traffic_manager.hpp @@ -215,6 +215,26 @@ public: */ void Push(traffxml::TraffFeed feed); + /** + * @brief Clears the entire traffic cache. + * + * This is currently called when the traffic manager is enabled or disabled. + * + * The old MWM traffic architecture was somewhat liberal in clearing its cache and re-fetching + * traffic data. This was possible because data was pre-processed and required no processing + * beyond deserialization, whereas TraFF data is more expensive to recreate. Also, the old + * architecture lacked any explicit notion of expiration; the app decided that data was to be + * considered stale after a certain period of time. TraFF, in contrast, has an explicit expiration + * time for each message, which can be anywhere from a few minutes to several weeks or months. + * Messages that have expired get deleted individually. + * For this reason, the TraFF message cache should not be cleared out under normal conditions + * (the main exception being tests). + * + * @todo Currently not implemented for TraFF; implement it for test purposes but do not call when + * the enabled state changes. + */ + void Clear(); + private: /** * @brief Holds information about pending or previous traffic requests pertaining to an MWM. @@ -365,9 +385,9 @@ private: /** * @brief Processes new traffic data. * - * @param trafficCache The new per-MWM colorings (preprocessed traffic information). + * The new per-MWM colorings (preprocessed traffic information) are taken from `m_allMmColoring`. */ - void OnTrafficDataUpdate(std::map &trafficCache); + void OnTrafficDataUpdate(); // TODO no longer needed #ifdef traffic_dead_code @@ -444,26 +464,6 @@ private: */ void RequestTrafficData(MwmSet::MwmId const & mwmId, bool force); - /** - * @brief Clears the entire traffic cache. - * - * This is currently called when the traffic manager is enabled or disabled. - * - * The old MWM traffic architecture was somewhat liberal in clearing its cache and re-fetching - * traffic data. This was possible because data was pre-processed and required no processing - * beyond deserialization, whereas TraFF data is more expensive to recreate. Also, the old - * architecture lacked any explicit notion of expiration; the app decided that data was to be - * considered stale after a certain period of time. TraFF, in contrast, has an explicit expiration - * time for each message, which can be anywhere from a few minutes to several weeks or months. - * Messages that have expired get deleted individually. - * For this reason, the TraFF message cache should not be cleared out under normal conditions - * (the main exception being tests). - * - * @todo Currently not implemented for TraFF; implement it for test purposes but do not call when - * the enabled state changes. - */ - void Clear(); - /** * @brief Removes traffic data for one specific MWM from the cache. * @@ -575,7 +575,7 @@ private: * * Invalidate(), clears the vector but not the set. * * UpdateActiveMwms(), uses the vector to detect changes. If so, it updates both vector and set. * - * Clear() clears both the set and the vector. + * Clear() clears both the set and the vector. (Clearing the set is currently disabled as it breaks ForEachActiveMwm.) */ std::vector m_lastDrapeMwmsByRect; std::set m_activeDrapeMwms; @@ -647,6 +647,10 @@ private: * @brief Cache of all currently active TraFF messages. * * Keys are message IDs, values are messages. + * + * Threads must lock `m_mutex` before accessing `m_messageCache`, as access can happen from + * multiple threads (messages are added by the worker thread, `Clear()` can be called from the UI + * thread). */ std::map m_messageCache; @@ -659,6 +663,10 @@ private: /** * @brief Map between MWM IDs and their colorings. + * + * Threads must lock `m_mutex` before accessing `m_allMwmColoring`, as access can happen from + * multiple threads (messages are added by the worker thread, `Clear()` can be called from the UI + * thread). */ std::map m_allMwmColoring; };