diff options
author | Daria Volvenkova <d.volvenkova@corp.mail.ru> | 2016-11-29 17:02:29 +0300 |
---|---|---|
committer | Daria Volvenkova <d.volvenkova@corp.mail.ru> | 2016-12-01 20:11:29 +0300 |
commit | fb61ac89e62a7e78cf112d1a021c62d369500790 (patch) | |
tree | 61b3129c9a534c9530eba4a1589d385743fac472 /map | |
parent | 961d4749e3a622b5027af9fe53441e01741170ff (diff) |
Logic of traffic manager's states.
Diffstat (limited to 'map')
-rw-r--r-- | map/framework.cpp | 29 | ||||
-rw-r--r-- | map/framework.hpp | 5 | ||||
-rw-r--r-- | map/traffic_manager.cpp | 251 | ||||
-rw-r--r-- | map/traffic_manager.hpp | 59 |
4 files changed, 307 insertions, 37 deletions
diff --git a/map/framework.cpp b/map/framework.cpp index 85446f0d11..c4f12f51e2 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -127,7 +127,7 @@ char const kTrafficEnabledKey[] = "TrafficEnabled"; double const kDistEqualQueryMeters = 100.0; -size_t constexpr kMaxTrafficCacheSizeBytes = 256 /* Mb */ * 1024 * 1024; +size_t constexpr kMaxTrafficCacheSizeBytes = 128 /* Mb */ * 1024 * 1024; // Must correspond SearchMarkType. vector<string> kSearchMarks = @@ -237,6 +237,11 @@ void Framework::SetMyPositionModeListener(TMyPositionModeChanged && fn) m_myPositionListener = move(fn); } +TrafficManager & Framework::GetTrafficManager() +{ + return m_trafficManager; +} + bool Framework::IsTrackingReporterEnabled() const { if (m_currentRouterType != routing::RouterType::Vehicle) @@ -318,7 +323,10 @@ void Framework::Migrate(bool keepDownloaded) // If we do not suspend drape, it tries to access framework fields (i.e. m_infoGetter) which are null // while migration is performed. if (m_drapeEngine && m_isRenderingEnabled) + { m_drapeEngine->SetRenderingDisabled(true); + OnDestroyGLContext(); + } m_selectedFeature = FeatureID(); m_searchEngine.reset(); m_infoGetter.reset(); @@ -330,11 +338,13 @@ void Framework::Migrate(bool keepDownloaded) InitCountryInfoGetter(); InitSearchEngine(); RegisterAllMaps(); + + m_trafficManager.SetCurrentDataVersion(GetStorage().GetCurrentDataVersion()); if (m_drapeEngine && m_isRenderingEnabled) { m_drapeEngine->SetRenderingEnabled(); - UpdateDrapeEngine(m_currentModelView.PixelRectIn3d().SizeX(), - m_currentModelView.PixelRectIn3d().SizeY()); + OnRecoverGLContext(m_currentModelView.PixelRectIn3d().SizeX(), + m_currentModelView.PixelRectIn3d().SizeY()); } InvalidateRect(MercatorBounds::FullRect()); } @@ -443,6 +453,8 @@ Framework::Framework() m_model.GetIndex().AddObserver(editor); LOG(LINFO, ("Editor initialized")); + + m_trafficManager.SetCurrentDataVersion(m_storage.GetCurrentDataVersion()); } Framework::~Framework() @@ -1711,7 +1723,7 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::OGLContextFactory> contextFactory, m_trafficManager.SetDrapeEngine(make_ref(m_drapeEngine)); } -void Framework::UpdateDrapeEngine(int width, int height) +void Framework::OnRecoverGLContext(int width, int height) { if (m_drapeEngine) { @@ -1722,9 +1734,14 @@ void Framework::UpdateDrapeEngine(int width, int height) UpdatePlacePageInfoForCurrentSelection(); m_drapeApi.Invalidate(); - - m_trafficManager.OnRecover(); } + + m_trafficManager.OnRecoverGLContext(); +} + +void Framework::OnDestroyGLContext() +{ + m_trafficManager.OnDestroyGLContext(); } ref_ptr<df::DrapeEngine> Framework::GetDrapeEngine() diff --git a/map/framework.hpp b/map/framework.hpp index e2b965113b..34ad4aa94f 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -448,7 +448,8 @@ public: void SetRenderingEnabled(ref_ptr<dp::OGLContextFactory> contextFactory = nullptr); void SetRenderingDisabled(bool destroyContext); - void UpdateDrapeEngine(int width, int height); + void OnRecoverGLContext(int width, int height); + void OnDestroyGLContext(); void SetFontScaleFactor(double scaleFactor); @@ -780,6 +781,8 @@ public: void AllowAutoZoom(bool allowAutoZoom); void SaveAutoZoom(bool allowAutoZoom); + TrafficManager & GetTrafficManager(); + bool LoadTrafficEnabled(); void SaveTrafficEnabled(bool trafficEnabled); diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp index cf5acfc085..0f65b1b129 100644 --- a/map/traffic_manager.cpp +++ b/map/traffic_manager.cpp @@ -1,5 +1,7 @@ #include "map/traffic_manager.hpp" +#include "platform/platform.hpp" + #include "routing/routing_helpers.hpp" #include "drape_frontend/drape_engine.hpp" @@ -10,14 +12,18 @@ namespace { -auto const kUpdateInterval = minutes(1); -} // namespace +auto constexpr kUpdateInterval = minutes(1); +auto constexpr kOutdatedDataTimeout = minutes(5) + kUpdateInterval; +auto constexpr kNetworkErrorTimeout = minutes(20); + +auto constexpr kMaxRetriesCount = 5; +} // namespace TrafficManager::TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes) - : m_isEnabled(false) - , m_getMwmsByRectFn(getMwmsByRectFn) + : m_getMwmsByRectFn(getMwmsByRectFn) + , m_state(TrafficState::Disabled) + , m_notifyStateChanged(false) , m_maxCacheSizeBytes(maxCacheSizeBytes) - , m_currentCacheSizeBytes(0) , m_isRunning(true) , m_thread(&TrafficManager::ThreadRoutine, this) { @@ -34,11 +40,41 @@ TrafficManager::~TrafficManager() m_thread.join(); } +void TrafficManager::SetStateListener(TrafficStateChangedFn const & onStateChangedFn) +{ + GetPlatform().RunOnGuiThread([this, onStateChangedFn]() + { + m_onStateChangedFn = onStateChangedFn; + }); +} + void TrafficManager::SetEnabled(bool enabled) { - m_isEnabled = enabled; + { + lock_guard<mutex> lock(m_requestedMwmsLock); + Clear(); + ChangeState(enabled ? TrafficState::Enabled : TrafficState::Disabled); + } + if (m_drapeEngine != nullptr) m_drapeEngine->EnableTraffic(enabled); + + if (enabled) + { + if (m_currentModelView.second) + UpdateViewport(m_currentModelView.first); + if (m_currentPosition.second) + UpdateMyPosition(m_currentPosition.first); + } + + NotifyStateChanged(); +} + +void TrafficManager::Clear() +{ + m_mwmCache.clear(); + m_activeMwms.clear(); + m_requestedMwms.clear(); } void TrafficManager::SetDrapeEngine(ref_ptr<df::DrapeEngine> engine) @@ -46,19 +82,38 @@ void TrafficManager::SetDrapeEngine(ref_ptr<df::DrapeEngine> engine) m_drapeEngine = engine; } -void TrafficManager::OnRecover() +void TrafficManager::SetCurrentDataVersion(int64_t dataVersion) { - m_mwmCache.clear(); + m_currentDataVersion = dataVersion; +} + +void TrafficManager::OnDestroyGLContext() +{ + if (!IsEnabled()) + return; + + { + lock_guard<mutex> lock(m_requestedMwmsLock); + Clear(); + } +} + +void TrafficManager::OnRecoverGLContext() +{ + if (!IsEnabled()) + return; - UpdateViewport(m_currentModelView); - UpdateMyPosition(m_currentPosition); + if (m_currentModelView.second) + UpdateViewport(m_currentModelView.first); + if (m_currentPosition.second) + UpdateMyPosition(m_currentPosition.first); } void TrafficManager::UpdateViewport(ScreenBase const & screen) { - m_currentModelView = screen; + m_currentModelView = {screen, true}; - if (!m_isEnabled) + if (!IsEnabled() || IsInvalidState()) return; if (df::GetZoomLevel(screen.GetScale()) < df::kRoadClass0ZoomLevel) @@ -74,18 +129,20 @@ void TrafficManager::UpdateViewport(ScreenBase const & screen) for (auto const & mwm : mwms) { if (mwm.IsAlive()) - m_activeMwms.push_back(mwm); + m_activeMwms.insert(mwm); } RequestTrafficData(); } + + NotifyStateChanged(); } void TrafficManager::UpdateMyPosition(MyPosition const & myPosition) { - m_currentPosition = myPosition; + m_currentPosition = {myPosition, true}; - if (!m_isEnabled) + if (!IsEnabled() || IsInvalidState()) return; // 1. Determine mwm's nearby "my position". @@ -102,12 +159,19 @@ void TrafficManager::ThreadRoutine() { for (auto const & mwm : mwms) { - traffic::TrafficInfo info(mwm); + traffic::TrafficInfo info(mwm, m_currentDataVersion); if (info.ReceiveTrafficData()) + { OnTrafficDataResponse(info); + } else + { LOG(LWARNING, ("Traffic request failed. Mwm =", mwm)); + OnTrafficRequestFailed(info); + } + + NotifyStateChanged(); } mwms.clear(); } @@ -116,12 +180,20 @@ void TrafficManager::ThreadRoutine() bool TrafficManager::WaitForRequest(vector<MwmSet::MwmId> & mwms) { unique_lock<mutex> lock(m_requestedMwmsLock); - bool const timeout = !m_condition.wait_for(lock, kUpdateInterval, [this] { return !m_isRunning || !m_requestedMwms.empty(); }); + + bool const timeout = !m_condition.wait_for(lock, kUpdateInterval, [this] + { + return !m_isRunning || !m_requestedMwms.empty(); + }); + if (!m_isRunning) return false; - if (timeout) + + if (timeout && IsEnabled() && !IsInvalidState()) { - mwms = m_activeMwms; + mwms.reserve(m_activeMwms.size()); + for (auto const & mwmId : m_activeMwms) + mwms.push_back(mwmId); } else { @@ -141,7 +213,7 @@ void TrafficManager::RequestTrafficData() ASSERT(mwmId.IsAlive(), ()); bool needRequesting = false; - auto currentTime = steady_clock::now(); + auto const currentTime = steady_clock::now(); auto it = m_mwmCache.find(mwmId); if (it == m_mwmCache.end()) @@ -156,6 +228,7 @@ void TrafficManager::RequestTrafficData() if (passedSeconds >= kUpdateInterval) { needRequesting = true; + it->second.m_isWaitingForResponse = true; it->second.m_lastRequestTime = currentTime; } } @@ -163,6 +236,8 @@ void TrafficManager::RequestTrafficData() if (needRequesting) RequestTrafficData(mwmId); } + + UpdateState(); } void TrafficManager::RequestTrafficData(MwmSet::MwmId const & mwmId) @@ -171,16 +246,57 @@ void TrafficManager::RequestTrafficData(MwmSet::MwmId const & mwmId) m_condition.notify_one(); } +void TrafficManager::OnTrafficRequestFailed(traffic::TrafficInfo const & info) +{ + lock_guard<mutex> lock(m_requestedMwmsLock); + + auto it = m_mwmCache.find(info.GetMwmId()); + if (it == m_mwmCache.end()) + return; + + it->second.m_isWaitingForResponse = false; + it->second.m_lastAvailability = info.GetAvailability(); + + if (info.GetAvailability() == traffic::TrafficInfo::Availability::Unknown) + { + if (!it->second.m_isLoaded) + { + if (m_activeMwms.find(info.GetMwmId()) != m_activeMwms.end()) + { + if (it->second.m_retriesCount < kMaxRetriesCount) + { + it->second.m_lastRequestTime = steady_clock::now(); + it->second.m_isWaitingForResponse = true; + RequestTrafficData(info.GetMwmId()); + } + ++it->second.m_retriesCount; + } + else + { + it->second.m_retriesCount = 0; + } + } + } + + UpdateState(); +} + void TrafficManager::OnTrafficDataResponse(traffic::TrafficInfo const & info) { + lock_guard<mutex> lock(m_requestedMwmsLock); + auto it = m_mwmCache.find(info.GetMwmId()); if (it == m_mwmCache.end()) return; + it->second.m_isLoaded = true; + it->second.m_lastResponseTime = steady_clock::now(); + it->second.m_isWaitingForResponse = false; + it->second.m_lastAvailability = info.GetAvailability(); + // Update cache. size_t constexpr kElementSize = sizeof(traffic::TrafficInfo::RoadSegmentId) + sizeof(traffic::SpeedGroup); size_t const dataSize = info.GetColoring().size() * kElementSize; - it->second.m_isLoaded = true; m_currentCacheSizeBytes += (dataSize - it->second.m_dataSize); it->second.m_dataSize = dataSize; CheckCacheSize(); @@ -189,6 +305,8 @@ void TrafficManager::OnTrafficDataResponse(traffic::TrafficInfo const & info) df::TrafficSegmentsColoring coloring; coloring[info.GetMwmId()] = info.GetColoring(); m_drapeEngine->UpdateTraffic(coloring); + + UpdateState(); } void TrafficManager::CheckCacheSize() @@ -215,3 +333,94 @@ void TrafficManager::CheckCacheSize() } } } + +bool TrafficManager::IsEnabled() const +{ + return m_state != TrafficState::Disabled; +} + +bool TrafficManager::IsInvalidState() const +{ + return m_state == TrafficState::NetworkError; +} + +void TrafficManager::UpdateState() +{ + if (!IsEnabled() || IsInvalidState()) + return; + + auto const currentTime = steady_clock::now(); + auto maxPassedTime = steady_clock::duration::zero(); + + bool waiting = false; + bool networkError = false; + bool expiredApp = false; + bool expiredMwm = false; + bool noData = false; + + for (auto const & mwmId : m_activeMwms) + { + auto it = m_mwmCache.find(mwmId); + ASSERT(it != m_mwmCache.end(), ()); + + if (it->second.m_isWaitingForResponse) + { + waiting = true; + } + else + { + expiredApp |= it->second.m_lastAvailability == traffic::TrafficInfo::Availability::ExpiredApp; + expiredMwm |= it->second.m_lastAvailability == traffic::TrafficInfo::Availability::ExpiredMwm; + noData |= it->second.m_lastAvailability == traffic::TrafficInfo::Availability::NoData; + } + + if (it->second.m_isLoaded) + { + auto const timeSinceLastResponse = currentTime - it->second.m_lastResponseTime; + if (timeSinceLastResponse > maxPassedTime) + maxPassedTime = timeSinceLastResponse; + } + else if (it->second.m_retriesCount >= kMaxRetriesCount) + { + networkError = true; + } + } + + if (networkError || maxPassedTime >= kNetworkErrorTimeout) + ChangeState(TrafficState::NetworkError); + else if (waiting) + ChangeState(TrafficState::WaitingData); + else if (expiredApp) + ChangeState(TrafficState::ExpiredApp); + else if (expiredMwm) + ChangeState(TrafficState::ExpiredData); + else if (noData) + ChangeState(TrafficState::NoData); + else if (maxPassedTime >= kOutdatedDataTimeout) + ChangeState(TrafficState::Outdated); + else + ChangeState(TrafficState::Enabled); +} + +void TrafficManager::ChangeState(TrafficState newState) +{ + if (m_state == newState) + return; + + m_state = newState; + m_notifyStateChanged = true; +} + +void TrafficManager::NotifyStateChanged() +{ + if (m_notifyStateChanged) + { + m_notifyStateChanged = false; + + GetPlatform().RunOnGuiThread([this]() + { + if (m_onStateChangedFn != nullptr) + m_onStateChangedFn(m_state); + }); + } +} diff --git a/map/traffic_manager.hpp b/map/traffic_manager.hpp index c8ccc17ace..87da904521 100644 --- a/map/traffic_manager.hpp +++ b/map/traffic_manager.hpp @@ -13,6 +13,7 @@ #include "indexer/index.hpp" #include "indexer/mwm_set.hpp" +#include "std/atomic.hpp" #include "std/chrono.hpp" #include "std/map.hpp" #include "std/mutex.hpp" @@ -28,6 +29,18 @@ class DrapeEngine; class TrafficManager final { public: + enum class TrafficState + { + Disabled, + Enabled, + WaitingData, + Outdated, + NoData, + NetworkError, + ExpiredData, + ExpiredApp + }; + struct MyPosition { m2::PointD m_position = m2::PointD(0.0, 0.0); @@ -40,57 +53,85 @@ public: {} }; + using TrafficStateChangedFn = function<void(TrafficState)>; using GetMwmsByRectFn = function<vector<MwmSet::MwmId>(m2::RectD const &)>; TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes); ~TrafficManager(); + void SetStateListener(TrafficStateChangedFn const & onStateChangedFn); + void SetDrapeEngine(ref_ptr<df::DrapeEngine> engine); + void SetCurrentDataVersion(int64_t dataVersion); + void SetEnabled(bool enabled); void UpdateViewport(ScreenBase const & screen); void UpdateMyPosition(MyPosition const & myPosition); - void OnRecover(); - - void SetDrapeEngine(ref_ptr<df::DrapeEngine> engine); + void OnDestroyGLContext(); + void OnRecoverGLContext(); private: void ThreadRoutine(); bool WaitForRequest(vector<MwmSet::MwmId> & mwms); + void RequestTrafficData(); void RequestTrafficData(MwmSet::MwmId const & mwmId); + void OnTrafficDataResponse(traffic::TrafficInfo const & info); + void OnTrafficRequestFailed(traffic::TrafficInfo const & info); + + void Clear(); void CheckCacheSize(); - bool m_isEnabled; + void UpdateState(); + void ChangeState(TrafficState newState); + void NotifyStateChanged(); + + bool IsInvalidState() const; + bool IsEnabled() const; GetMwmsByRectFn m_getMwmsByRectFn; ref_ptr<df::DrapeEngine> m_drapeEngine; + int64_t m_currentDataVersion = 0; + + pair<MyPosition, bool> m_currentPosition = {MyPosition(), false}; + pair<ScreenBase, bool> m_currentModelView = {ScreenBase(), false}; - MyPosition m_currentPosition; - ScreenBase m_currentModelView; + atomic<TrafficState> m_state; + atomic<bool> m_notifyStateChanged; + TrafficStateChangedFn m_onStateChangedFn; struct CacheEntry { CacheEntry() = default; CacheEntry(time_point<steady_clock> const & requestTime) : m_lastRequestTime(requestTime) {} + bool m_isLoaded = false; + size_t m_dataSize = 0; + time_point<steady_clock> m_lastSeenTime; time_point<steady_clock> m_lastRequestTime; - size_t m_dataSize = 0; + time_point<steady_clock> m_lastResponseTime; + + uint32_t m_retriesCount = 0; + bool m_isWaitingForResponse = false; + + traffic::TrafficInfo::Availability m_lastAvailability = + traffic::TrafficInfo::Availability::Unknown; }; size_t m_maxCacheSizeBytes; - size_t m_currentCacheSizeBytes; + size_t m_currentCacheSizeBytes = 0; map<MwmSet::MwmId, CacheEntry> m_mwmCache; bool m_isRunning; condition_variable m_condition; - vector<MwmSet::MwmId> m_activeMwms; + set<MwmSet::MwmId> m_activeMwms; vector<MwmSet::MwmId> m_requestedMwms; mutex m_requestedMwmsLock; |