From b81b956937f1bc0ebae408c7f81394a54cec14bf Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Mon, 21 Nov 2016 16:05:36 +0300 Subject: [PATCH] Logic of clearing traffic cached data. --- map/framework.cpp | 5 +- map/traffic_manager.cpp | 128 +++++++++++++++++++++++++++------------- map/traffic_manager.hpp | 25 ++++++-- 3 files changed, 113 insertions(+), 45 deletions(-) diff --git a/map/framework.cpp b/map/framework.cpp index 6a7b95527b..bb334c421b 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -124,6 +124,8 @@ char const kAllowAutoZoom[] = "AutoZoom"; double const kDistEqualQueryMeters = 100.0; +size_t constexpr kMaxTrafficCacheSizeBytes = 256 /* Mb */ * 1024 * 1024; + // Must correspond SearchMarkType. vector kSearchMarks = { @@ -341,7 +343,8 @@ Framework::Framework() , m_isRenderingEnabled(true) , m_trackingReporter(platform::CreateSocket(), TRACKING_REALTIME_HOST, TRACKING_REALTIME_PORT, tracking::Reporter::kPushDelayMs) - , m_trafficManager(m_model.GetIndex(), bind(&Framework::GetMwmsByRect, this, _1)) + , m_trafficManager(m_model.GetIndex(), bind(&Framework::GetMwmsByRect, this, _1), + kMaxTrafficCacheSizeBytes) , m_displacementModeManager([this](bool show) { int const mode = show ? dp::displacement::kHotelMode : dp::displacement::kDefaultMode; CallDrapeFunction(bind(&df::DrapeEngine::SetDisplacementMode, _1, mode)); diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp index 33aac76238..a614608094 100644 --- a/map/traffic_manager.cpp +++ b/map/traffic_manager.cpp @@ -3,19 +3,25 @@ #include "routing/routing_helpers.hpp" #include "drape_frontend/drape_engine.hpp" +#include "drape_frontend/visual_params.hpp" #include "indexer/scales.hpp" namespace { -seconds const kUpdateInterval = minutes(5); +auto const kUpdateInterval = minutes(1); + +int const kMinTrafficZoom = 10; + } // namespace -TrafficManager::TrafficManager(Index const & index, - GetMwmsByRectFn const & getMwmsByRectFn) - : m_isEnabled(true) //TODO: true is temporary +TrafficManager::TrafficManager(Index const & index, GetMwmsByRectFn const & getMwmsByRectFn, + size_t maxCacheSizeBytes) + : m_isEnabled(true) // TODO: true is temporary , m_index(index) , m_getMwmsByRectFn(getMwmsByRectFn) + , m_maxCacheSizeBytes(maxCacheSizeBytes) + , m_currentCacheSizeBytes(0) , m_isRunning(true) , m_thread(&TrafficManager::ThreadRoutine, this) { @@ -44,8 +50,7 @@ void TrafficManager::SetDrapeEngine(ref_ptr engine) void TrafficManager::OnRecover() { - m_requestTimings.clear(); - m_mwmIds.clear(); + m_mwmInfos.clear(); UpdateViewport(m_currentModelView); UpdateMyPosition(m_currentPosition); @@ -58,19 +63,24 @@ void TrafficManager::UpdateViewport(ScreenBase const & screen) if (!m_isEnabled) return; + if (df::GetZoomLevel(screen.GetScale()) < kMinTrafficZoom) + return; + // Request traffic. auto mwms = m_getMwmsByRectFn(screen.ClipRect()); - for (auto const & mwm : mwms) - { - if (mwm.IsAlive()) - RequestTrafficData(mwm); - } - // TODO: Remove some mwm's from cache. - //MwmSet::MwmId mwmId; - //m_drapeEngine->ClearTrafficCache(mwmId); - // TODO: remove from m_requestTimings - // TODO: remove from m_mwmIds + { + lock_guard lock(m_requestedMwmsLock); + + m_activeMwms.clear(); + for (auto const & mwm : mwms) + { + if (mwm.IsAlive()) + m_activeMwms.push_back(mwm); + } + + RequestTrafficData(); + } } void TrafficManager::UpdateMyPosition(MyPosition const & myPosition) @@ -164,9 +174,7 @@ bool TrafficManager::WaitForRequest(vector & mwms) return false; if (timeout) { - mwms.reserve(m_requestTimings.size()); - for (auto const & timing : m_requestTimings) - mwms.push_back(timing.first); + mwms = m_activeMwms; } else { @@ -176,34 +184,38 @@ bool TrafficManager::WaitForRequest(vector & mwms) return true; } -void TrafficManager::RequestTrafficData(MwmSet::MwmId const & mwmId) +void TrafficManager::RequestTrafficData() { - lock_guard lock(m_requestedMwmsLock); + if (m_activeMwms.empty()) + return; - ASSERT(mwmId.IsAlive(), ()); - bool needRequesting = false; + for (auto const & mwmId : m_activeMwms) + { + ASSERT(mwmId.IsAlive(), ()); + bool needRequesting = false; - auto it = m_requestTimings.find(mwmId); - if (it == m_requestTimings.end()) - { - needRequesting = true; - m_requestTimings[mwmId] = steady_clock::now(); - } - else - { - auto const passedSeconds = steady_clock::now() - it->second; - if (passedSeconds >= kUpdateInterval) + auto it = m_mwmInfos.find(mwmId); + if (it == m_mwmInfos.end()) { needRequesting = true; - it->second = steady_clock::now(); + m_mwmInfos.insert(make_pair(mwmId, MwmTrafficInfo(steady_clock::now()))); + } + else + { + auto const passedSeconds = steady_clock::now() - it->second.m_lastRequestTime; + if (passedSeconds >= kUpdateInterval) + { + needRequesting = true; + it->second.m_lastRequestTime = steady_clock::now(); + } } - } - if (needRequesting) - RequestTrafficDataImpl(mwmId); + if (needRequesting) + RequestTrafficData(mwmId); + } } -void TrafficManager::RequestTrafficDataImpl(MwmSet::MwmId const & mwmId) +void TrafficManager::RequestTrafficData(MwmSet::MwmId const & mwmId) { m_requestedMwms.push_back(mwmId); m_condition.notify_one(); @@ -211,17 +223,53 @@ void TrafficManager::RequestTrafficDataImpl(MwmSet::MwmId const & mwmId) void TrafficManager::OnTrafficDataResponse(traffic::TrafficInfo const & info) { + auto it = m_mwmInfos.find(info.GetMwmId()); + if (it == m_mwmInfos.end()) + return; + // Cache geometry for rendering if it's necessary. - if (m_mwmIds.find(info.GetMwmId()) == m_mwmIds.end()) + if (!it->second.m_isLoaded) { df::TrafficSegmentsGeometry geometry; CalculateSegmentsGeometry(info, geometry); - m_mwmIds.insert(info.GetMwmId()); + it->second.m_isLoaded = true; m_drapeEngine->CacheTrafficSegmentsGeometry(geometry); } // Update traffic colors. df::TrafficSegmentsColoring coloring; CalculateSegmentsColoring(info, coloring); + + size_t dataSize = coloring.size() * sizeof(df::TrafficSegmentColoring); + it->second.m_dataSize = dataSize; + m_currentCacheSizeBytes += dataSize; + + CheckCacheSize(); + m_drapeEngine->UpdateTraffic(coloring); } + +void TrafficManager::CheckCacheSize() +{ + if ((m_currentCacheSizeBytes > m_maxCacheSizeBytes) && (m_mwmInfos.size() > m_activeMwms.size())) + { + std::multimap, MwmSet::MwmId> seenTimings; + for (auto const & mwmInfo : m_mwmInfos) + seenTimings.insert(make_pair(mwmInfo.second.m_lastSeenTime, mwmInfo.first)); + + auto itSeen = seenTimings.begin(); + while ((m_currentCacheSizeBytes > m_maxCacheSizeBytes) && + (m_mwmInfos.size() > m_activeMwms.size())) + { + auto const mwmId = itSeen->second; + auto const it = m_mwmInfos.find(mwmId); + if (it->second.m_isLoaded) + { + m_currentCacheSizeBytes -= it->second.m_dataSize; + m_drapeEngine->ClearTrafficCache(mwmId); + } + m_mwmInfos.erase(it); + ++itSeen; + } + } +} diff --git a/map/traffic_manager.hpp b/map/traffic_manager.hpp index f2ca8dcda2..9a209fe8a0 100644 --- a/map/traffic_manager.hpp +++ b/map/traffic_manager.hpp @@ -42,7 +42,8 @@ public: using GetMwmsByRectFn = function(m2::RectD const &)>; - TrafficManager(Index const & index, GetMwmsByRectFn const & getMwmsByRectFn); + TrafficManager(Index const & index, GetMwmsByRectFn const & getMwmsByRectFn, + size_t maxCacheSizeBytes); ~TrafficManager(); void SetEnabled(bool enabled); @@ -62,9 +63,10 @@ private: void ThreadRoutine(); bool WaitForRequest(vector & mwms); + void RequestTrafficData(); void RequestTrafficData(MwmSet::MwmId const & mwmId); - void RequestTrafficDataImpl(MwmSet::MwmId const & mwmId); void OnTrafficDataResponse(traffic::TrafficInfo const & info); + void CheckCacheSize(); bool m_isEnabled; @@ -76,12 +78,27 @@ private: MyPosition m_currentPosition; ScreenBase m_currentModelView; - set m_mwmIds; - map> m_requestTimings; + struct MwmTrafficInfo + { + MwmTrafficInfo() = default; + + MwmTrafficInfo(time_point const & requestTime) : m_lastRequestTime(requestTime) {} + bool m_isLoaded = false; + time_point m_lastSeenTime; + time_point m_lastRequestTime; + size_t m_dataSize = 0; + }; + + size_t m_maxCacheSizeBytes; + size_t m_currentCacheSizeBytes; + + map m_mwmInfos; bool m_isRunning; condition_variable m_condition; + vector m_activeMwms; + vector m_requestedMwms; mutex m_requestedMwmsLock; thread m_thread;