Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/map
diff options
context:
space:
mode:
authorDaria Volvenkova <d.volvenkova@corp.mail.ru>2016-11-29 17:02:29 +0300
committerDaria Volvenkova <d.volvenkova@corp.mail.ru>2016-12-01 20:11:29 +0300
commitfb61ac89e62a7e78cf112d1a021c62d369500790 (patch)
tree61b3129c9a534c9530eba4a1589d385743fac472 /map
parent961d4749e3a622b5027af9fe53441e01741170ff (diff)
Logic of traffic manager's states.
Diffstat (limited to 'map')
-rw-r--r--map/framework.cpp29
-rw-r--r--map/framework.hpp5
-rw-r--r--map/traffic_manager.cpp251
-rw-r--r--map/traffic_manager.hpp59
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;