diff options
author | gorshenin <y.gorshenin@corp.mail.ru> | 2015-07-01 16:48:58 +0300 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 02:53:27 +0300 |
commit | a7bcdb5ae8b8e75c1a3806b00b19f3b80c72c5b3 (patch) | |
tree | e24caedef110b579fcedc15d29c62cc43e3f6d9c | |
parent | e0470160313b3ed0bc396ffec72b16fded6b8520 (diff) |
Revert "[storage, framework, index] Storage redesign. Plain strings are replaced to CountryFile and LocalCountryFile."
66 files changed, 1923 insertions, 2514 deletions
diff --git a/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp b/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp index bd6993716b..1b6b3c9067 100644 --- a/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp +++ b/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp @@ -3,10 +3,9 @@ #include "defines.hpp" -#include "coding/file_name_utils.hpp" -#include "coding/internal/file_data.hpp" -#include "coding/reader_streambuf.hpp" #include "coding/url_encode.hpp" +#include "coding/reader_streambuf.hpp" +#include "coding/internal/file_data.hpp" #include "platform/platform.hpp" #include "platform/http_request.hpp" @@ -213,11 +212,7 @@ extern "C" storage::Storage const & storage = g_framework->Storage(); for (size_t i = 0; i < curFile.m_urls.size(); ++i) { - string baseName = curFile.m_fileName; - my::GetNameWithoutExt(baseName); - storage::TIndex const index = storage.FindIndexByFile(baseName); - - curFile.m_urls[i] = storage.GetFileDownloadUrl(curFile.m_urls[i], index, TMapOptions::EMap); + curFile.m_urls[i] = storage.GetFileDownloadUrl(curFile.m_urls[i], curFile.m_fileName); LOG(LDEBUG, (curFile.m_urls[i])); } diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 6e9f751f5d..957e150873 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -23,11 +23,8 @@ #include "geometry/angles.hpp" -#include "platform/country_file.hpp" -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" -#include "platform/location.hpp" #include "platform/measurement_utils.hpp" +#include "platform/location.hpp" #include "platform/platform.hpp" #include "platform/preferred_languages.hpp" @@ -48,8 +45,6 @@ const double DOUBLE_TOUCH_S = SHORT_TOUCH_MS / 1000.0; android::Framework * g_framework = 0; using namespace storage; -using platform::CountryFile; -using platform::LocalCountryFile; namespace { @@ -558,32 +553,33 @@ namespace android void Framework::GetMapsWithoutSearch(vector<string> & out) const { - ASSERT(out.empty(), ()); + ASSERT ( out.empty(), () ); ::Platform const & pl = GetPlatform(); - vector<LocalCountryFile> localFiles; - platform::FindAllLocalMaps(localFiles); + vector<string> v; + m_work.GetMaps(v); - for (LocalCountryFile const & localFile : localFiles) + for (size_t i = 0; i < v.size(); ++i) { - CountryFile const countryFile = localFile.GetCountryFile(); // skip World and WorldCoast - if (countryFile.GetNameWithoutExt() == WORLD_FILE_NAME || - countryFile.GetNameWithoutExt() == WORLD_COASTS_FILE_NAME) - { - continue; - } - try - { - FilesContainerR cont(pl.GetCountryReader(localFile, TMapOptions::EMap)); - if (!cont.IsExist(SEARCH_INDEX_FILE_TAG)) - out.push_back(countryFile.GetNameWithoutExt()); - } - catch (RootException const & ex) + if (v[i].find(WORLD_FILE_NAME) == string::npos && + v[i].find(WORLD_COASTS_FILE_NAME) == string::npos) { - // sdcard can contain dummy _*.mwm files. Suppress these errors. - LOG(LWARNING, ("Bad mwm file:", countryFile.GetNameWithoutExt(), "Error:", ex.Msg())); + try + { + FilesContainerR cont(pl.GetReader(v[i])); + if (!cont.IsExist(SEARCH_INDEX_FILE_TAG)) + { + my::GetNameWithoutExt(v[i]); + out.push_back(v[i]); + } + } + catch (RootException const & ex) + { + // sdcard can contain dummy _*.mwm files. Supress this errors. + LOG(LWARNING, ("Bad mwm file:", v[i], "Error:", ex.Msg())); + } } } } diff --git a/drape_head/drape_surface.cpp b/drape_head/drape_surface.cpp index c1c431ebfa..76df4004da 100644 --- a/drape_head/drape_surface.cpp +++ b/drape_head/drape_surface.cpp @@ -28,13 +28,13 @@ DrapeSurface::DrapeSurface() ///{ Temporary initialization m_model.InitClassificator(); - // Platform::FilesList maps; - // Platform & pl = GetPlatform(); - // pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps); + Platform::FilesList maps; + Platform & pl = GetPlatform(); + pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps); - // for_each(maps.begin(), maps.end(), bind(&model::FeaturesFetcher::RegisterMap, &m_model, _1)); - // ///} - // /// + for_each(maps.begin(), maps.end(), bind(&model::FeaturesFetcher::RegisterMap, &m_model, _1)); + ///} + /// } DrapeSurface::~DrapeSurface() diff --git a/generator/generator_tests/check_mwms.cpp b/generator/generator_tests/check_mwms.cpp index 1ce869d62c..b4771110ba 100644 --- a/generator/generator_tests/check_mwms.cpp +++ b/generator/generator_tests/check_mwms.cpp @@ -5,8 +5,6 @@ #include "indexer/data_header.hpp" #include "indexer/interval_index.hpp" -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" #include "platform/platform.hpp" #include "base/logging.hpp" @@ -14,25 +12,25 @@ UNIT_TEST(CheckMWM_LoadAll) { - Platform & platform = GetPlatform(); - vector<platform::LocalCountryFile> localFiles; - platform::FindAllLocalMapsInDirectory(platform.WritableDir(), 0 /* version */, localFiles); + Platform & pl = GetPlatform(); + + Platform::FilesList maps; + pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps); model::FeaturesFetcher m; m.InitClassificator(); - for (platform::LocalCountryFile const & localFile : localFiles) + for (string const & s : maps) { - LOG(LINFO, ("Found mwm:", localFile)); try { - pair<MwmSet::MwmLock, bool> const p = m.RegisterMap(localFile); + pair<MwmSet::MwmLock, bool> const p = m.RegisterMap(s); TEST(p.first.IsLocked(), ()); TEST(p.second, ()); } catch (RootException const & ex) { - TEST(false, ("Bad mwm file:", localFile)); + TEST(false, ("Bad mwm file:", s)); } } } diff --git a/generator/routing_generator.cpp b/generator/routing_generator.cpp index 2f37a187a3..5827019b9b 100644 --- a/generator/routing_generator.cpp +++ b/generator/routing_generator.cpp @@ -30,9 +30,6 @@ #include "3party/osrm/osrm-backend/data_structures/query_edge.hpp" #include "3party/osrm/osrm-backend/data_structures/internal_route_result.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; - namespace routing { @@ -226,13 +223,9 @@ void BuildRoutingIndex(string const & baseDir, string const & countryName, strin { classificator::Load(); - CountryFile countryFile(countryName); - - // Correct mwm version doesn't matter here - we just need access to mwm files via Index. - LocalCountryFile localFile(baseDir, countryFile, 0 /* version */); - localFile.SyncWithDisk(); + string const mwmFile = baseDir + countryName + DATA_FILE_EXTENSION; Index index; - pair<MwmSet::MwmLock, bool> const p = index.Register(localFile); + pair<MwmSet::MwmLock, bool> const p = index.Register(mwmFile); if (!p.second) { LOG(LCRITICAL, ("MWM file not found")); @@ -242,7 +235,7 @@ void BuildRoutingIndex(string const & baseDir, string const & countryName, strin osrm::NodeDataVectorT nodeData; gen::OsmID2FeatureID osm2ft; - if (!LoadIndexes(localFile.GetPath(TMapOptions::EMap), osrmFile, nodeData, osm2ft)) + if (!LoadIndexes(mwmFile, osrmFile, nodeData, osm2ft)) return; OsrmFtSegMappingBuilder mapping; @@ -373,13 +366,13 @@ void BuildRoutingIndex(string const & baseDir, string const & countryName, strin "Multiple:", multiple, "Equal:", equal)); LOG(LINFO, ("Collect all data into one file...")); - string const fPath = localFile.GetPath(TMapOptions::ECarRouting); + string const fPath = mwmFile + ROUTING_FILE_EXTENSION; FilesContainerW routingCont(fPath /*, FileWriter::OP_APPEND*/); { // Write version for routing file that is equal to correspondent mwm file. - FilesContainerR mwmCont(localFile.GetPath(TMapOptions::EMap)); + FilesContainerR mwmCont(mwmFile); FileWriter w = routingCont.GetWriter(VERSION_FILE_TAG); ReaderSource<ModelReaderPtr> src(mwmCont.GetReader(VERSION_FILE_TAG)); diff --git a/generator/update_generator.cpp b/generator/update_generator.cpp index 2653e281ad..9d8cda8d45 100644 --- a/generator/update_generator.cpp +++ b/generator/update_generator.cpp @@ -43,10 +43,10 @@ namespace update string m_dataDir; Platform::FilesList & m_files; - uint64_t GetFileSize(platform::CountryFile const & cnt, TMapOptions opt) const + uint64_t GetFileSize(CountryFile const & cnt, TMapOptions opt) const { uint64_t sz = 0; - string const fName = cnt.GetNameWithExt(opt); + string const fName = cnt.GetFileWithExt(opt); if (!GetPlatform().GetFileSizeByFullPath(m_dataDir + fName, sz)) { LOG(opt == TMapOptions::EMap ? LCRITICAL : LWARNING, ("File was not found:", fName)); @@ -74,14 +74,14 @@ namespace update { for (size_t i = 0; i < c.Value().m_files.size(); ++i) { - platform::CountryFile & cnt = c.Value().m_files[i]; + CountryFile & cnt = c.Value().m_files[i]; ++m_processedFiles; - cnt.SetRemoteSizes(GetFileSize(cnt, TMapOptions::EMap), - GetFileSize(cnt, TMapOptions::ECarRouting)); + cnt.AssignSizes(GetFileSize(cnt, TMapOptions::EMap), + GetFileSize(cnt, TMapOptions::ECarRouting)); - string const fName = cnt.GetNameWithExt(TMapOptions::EMap); + string const fName = cnt.GetFileWithoutExt() + DATA_FILE_EXTENSION; auto found = find(m_files.begin(), m_files.end(), fName); if (found != m_files.end()) m_files.erase(found); diff --git a/indexer/index.cpp b/indexer/index.cpp index 12d0a02fe7..e27814dc74 100644 --- a/indexer/index.cpp +++ b/indexer/index.cpp @@ -6,27 +6,32 @@ #include "coding/file_name_utils.hpp" #include "coding/internal/file_data.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; ////////////////////////////////////////////////////////////////////////////////// // MwmValue implementation ////////////////////////////////////////////////////////////////////////////////// -MwmValue::MwmValue(LocalCountryFile const & localFile) - : m_cont(GetPlatform().GetCountryReader(localFile, TMapOptions::EMap)), - m_countryFile(localFile.GetCountryFile()) +MwmValue::MwmValue(string const & name) + : m_cont(GetPlatform().GetReader(name)) { m_factory.Load(m_cont); } +string MwmValue::GetFileName() const +{ + string s = m_cont.GetFileName(); + my::GetNameFromFullPath(s); + my::GetNameWithoutExt(s); + return s; +} + ////////////////////////////////////////////////////////////////////////////////// // Index implementation ////////////////////////////////////////////////////////////////////////////////// -bool Index::GetVersion(LocalCountryFile const & localFile, MwmInfo & info) const +bool Index::GetVersion(string const & name, MwmInfo & info) const { - MwmValue value(localFile); + MwmValue value(name); feature::DataHeader const & h = value.GetHeader(); if (!h.IsMWMSuitable()) @@ -42,9 +47,9 @@ bool Index::GetVersion(LocalCountryFile const & localFile, MwmInfo & info) const return true; } -MwmSet::TMwmValueBasePtr Index::CreateValue(LocalCountryFile const & localFile) const +MwmSet::TMwmValueBasePtr Index::CreateValue(string const & name) const { - TMwmValueBasePtr p(new MwmValue(localFile)); + TMwmValueBasePtr p(new MwmValue(name)); ASSERT(static_cast<MwmValue &>(*p.get()).GetHeader().IsMWMSuitable(), ()); return p; } @@ -58,23 +63,124 @@ Index::~Index() Cleanup(); } -pair<MwmSet::MwmLock, bool> Index::RegisterMap(LocalCountryFile const & localFile) +namespace { - pair<MwmSet::MwmLock, bool> result = Register(localFile); - if (result.first.IsLocked() && result.second) - m_observers.ForEach(&Observer::OnMapRegistered, localFile); + // Deletes map file denoted by @path and all temporary files related + // to it. + void DeleteMapFiles(string const & path, bool deleteReady) + { + (void)my::DeleteFileX(path); + (void)my::DeleteFileX(path + RESUME_FILE_EXTENSION); + (void)my::DeleteFileX(path + DOWNLOADING_FILE_EXTENSION); + + if (deleteReady) + (void)my::DeleteFileX(path + READY_FILE_EXTENSION); + } + + string GetFullPath(string const & fileName) + { + return GetPlatform().WritablePathForFile(fileName); + } + + // Deletes all files related to @fileName and renames + // @fileName.READY_FILE_EXTENSION to @fileName. + void ReplaceFileWithReady(string const & fileName) + { + string const path = GetFullPath(fileName); + DeleteMapFiles(path, false /* deleteReady */); + CHECK(my::RenameFileX(path + READY_FILE_EXTENSION, path), (path)); + } +} + +pair<MwmSet::MwmLock, bool> Index::RegisterMap(string const & fileName) +{ + if (GetPlatform().IsFileExistsByFullPath(GetFullPath(fileName + READY_FILE_EXTENSION))) + { + pair<MwmSet::MwmLock, UpdateStatus> updateResult = UpdateMap(fileName); + switch (updateResult.second) + { + case UPDATE_STATUS_OK: + return make_pair(move(updateResult.first), true); + case UPDATE_STATUS_BAD_FILE: + return make_pair(move(updateResult.first), false); + case UPDATE_STATUS_UPDATE_DELAYED: + // Not dangerous, but it's strange when adding existing maps. + ASSERT(false, ()); + return make_pair(move(updateResult.first), true); + } + } + + pair<MwmSet::MwmLock, bool> result = Register(fileName); + if (result.second) + m_observers.ForEach(&Observer::OnMapRegistered, fileName); return result; } -bool Index::DeregisterMap(CountryFile const & countryFile) { return Deregister(countryFile); } +bool Index::DeleteMap(string const & fileName) +{ + { + lock_guard<mutex> lock(m_lock); + + if (!DeregisterImpl(fileName)) + return false; + + DeleteMapFiles(GetFullPath(fileName), true /* deleteReady */); + } + m_observers.ForEach(&Observer::OnMapDeleted, fileName); + return true; +} bool Index::AddObserver(Observer & observer) { return m_observers.Add(observer); } bool Index::RemoveObserver(Observer const & observer) { return m_observers.Remove(observer); } -void Index::OnMwmDeregistered(LocalCountryFile const & localFile) +pair<MwmSet::MwmLock, Index::UpdateStatus> Index::UpdateMap(string const & fileName) +{ + pair<MwmSet::MwmLock, UpdateStatus> result; + result.second = UPDATE_STATUS_BAD_FILE; + + { + lock_guard<mutex> lock(m_lock); + + MwmId const id = GetMwmIdByFileNameImpl(fileName); + shared_ptr<MwmInfo> info = id.GetInfo(); + if (id.IsAlive() && info->m_lockCount > 0) + { + info->SetStatus(MwmInfo::STATUS_PENDING_UPDATE); + result.first = GetLock(id); + result.second = UPDATE_STATUS_UPDATE_DELAYED; + } + else + { + ReplaceFileWithReady(fileName); + pair<MwmSet::MwmLock, bool> registerResult = RegisterImpl(fileName); + if (registerResult.second) + { + result.first = move(registerResult.first); + result.second = UPDATE_STATUS_OK; + } + } + } + if (result.second != UPDATE_STATUS_BAD_FILE) + m_observers.ForEach(&Observer::OnMapUpdateIsReady, fileName); + if (result.second == UPDATE_STATUS_OK) + m_observers.ForEach(&Observer::OnMapUpdated, fileName); + return result; +} + +void Index::OnMwmDeleted(shared_ptr<MwmInfo> const & info) +{ + string const & fileName = info->m_fileName; + DeleteMapFiles(fileName, true /* deleteReady */); + m_observers.ForEach(&Observer::OnMapDeleted, fileName); +} + +void Index::OnMwmReadyForUpdate(shared_ptr<MwmInfo> const & info) { - m_observers.ForEach(&Observer::OnMapDeregistered, localFile); + ClearCache(MwmId(info)); + ReplaceFileWithReady(info->m_fileName); + info->SetStatus(MwmInfo::STATUS_UP_TO_DATE); + m_observers.ForEach(&Observer::OnMapUpdated, info->m_fileName); } ////////////////////////////////////////////////////////////////////////////////// @@ -88,11 +194,11 @@ Index::FeaturesLoaderGuard::FeaturesLoaderGuard(Index const & parent, MwmId id) { } -string Index::FeaturesLoaderGuard::GetCountryFileName() const +string Index::FeaturesLoaderGuard::GetFileName() const { if (!m_lock.IsLocked()) return string(); - return m_lock.GetValue<MwmValue>()->GetCountryFile().GetNameWithoutExt(); + return m_lock.GetValue<MwmValue>()->GetFileName(); } bool Index::FeaturesLoaderGuard::IsWorld() const diff --git a/indexer/index.hpp b/indexer/index.hpp index 20d9d75c5d..c058a0f11b 100644 --- a/indexer/index.hpp +++ b/indexer/index.hpp @@ -24,25 +24,33 @@ class MwmValue : public MwmSet::MwmValueBase public: FilesContainerR m_cont; IndexFactory m_factory; - platform::CountryFile const m_countryFile; - explicit MwmValue(platform::LocalCountryFile const & localFile); + explicit MwmValue(string const & name); inline feature::DataHeader const & GetHeader() const { return m_factory.GetHeader(); } inline version::MwmVersion const & GetMwmVersion() const { return m_factory.GetMwmVersion(); } - inline platform::CountryFile const & GetCountryFile() const { return m_countryFile; } + /// @return MWM file name without extension. + string GetFileName() const; }; class Index : public MwmSet { protected: // MwmSet overrides: - bool GetVersion(platform::LocalCountryFile const & localFile, MwmInfo & info) const override; - TMwmValueBasePtr CreateValue(platform::LocalCountryFile const & localFile) const override; - void OnMwmDeregistered(platform::LocalCountryFile const & localFile) override; + bool GetVersion(string const & name, MwmInfo & info) const override; + TMwmValueBasePtr CreateValue(string const & name) const override; + void OnMwmDeleted(shared_ptr<MwmInfo> const & info) override; + void OnMwmReadyForUpdate(shared_ptr<MwmInfo> const & info) override; public: + enum UpdateStatus + { + UPDATE_STATUS_OK, + UPDATE_STATUS_BAD_FILE, + UPDATE_STATUS_UPDATE_DELAYED + }; + /// An Observer interface to MwmSet. Note that these functions can /// be called from *ANY* thread because most signals are sent when /// some thread releases its MwmLock, so overrides must be as fast @@ -50,14 +58,19 @@ public: class Observer { public: - virtual ~Observer() = default; + virtual ~Observer() {} + + /// Called when a map is registered for a first time. + virtual void OnMapRegistered(string const & file) {} - /// Called when a map is registered for a first time and can be - /// used. - virtual void OnMapRegistered(platform::LocalCountryFile const & localFile) {} + /// Called when an update for a map is downloaded. + virtual void OnMapUpdateIsReady(string const & file) {} - /// Called when a map is deregistered and can not be used. - virtual void OnMapDeregistered(platform::LocalCountryFile const & localFile) {} + /// Called when an update for a map is applied. + virtual void OnMapUpdated(string const & file) {} + + /// Called when a map is deleted. + virtual void OnMapDeleted(string const & file) {} }; Index(); @@ -65,21 +78,37 @@ public: /// Registers a new map. /// - /// \return A pair of an MwmLock and a flag. There are three cases: - /// * the map is newer than the newest registered - returns - /// active lock and set flag - /// * the map is older than the newest registered - returns inactive lock and - /// unset flag. - /// * the version of the map equals to the version of the newest registered - - /// returns active lock and unset flag. - WARN_UNUSED_RESULT pair<MwmLock, bool> RegisterMap(platform::LocalCountryFile const & localFile); - - /// Deregisters a map from internal records. + /// \return A pair of an MwmLock and a flag. MwmLock is locked iff the + /// map with fileName was created or already exists. Flag + /// is set when the map was registered for a first + /// time. Thus, there are three main cases: + /// + /// * the map already exists - returns active lock and unset flag + /// * the map was already registered - returns active lock and set flag + /// * the map can't be registered - returns inactive lock and unset flag + WARN_UNUSED_RESULT pair<MwmLock, bool> RegisterMap(string const & fileName); + + /// Replaces a map file corresponding to fileName with a new one, when + /// it's possible - no clients of the map file. Otherwise, update + /// will be delayed. + /// + /// \return * the map file have been updated - returns active lock and + /// UPDATE_STATUS_OK + /// * update is delayed because the map is busy - returns active lock and + /// UPDATE_STATUS_UPDATE_DELAYED + /// * the file isn't suitable for update - returns inactive lock and + /// UPDATE_STATUS_BAD_FILE + WARN_UNUSED_RESULT pair<MwmLock, UpdateStatus> UpdateMap(string const & fileName); + + /// Deletes a map both from the file system and internal tables, also, + /// deletes all files related to the map. If the map was successfully + /// deleted, notifies observers. /// - /// \param countryFile A countryFile denoting a map to be deregistered. - /// \return True if the map was successfully deregistered. If map is locked - /// now, returns false. - bool DeregisterMap(platform::CountryFile const & countryFile); + /// \param fileName A fileName denoting the map to be deleted, may + /// be a full path or a short path relative to + /// executable's directories. + //// \return True if the map was successfully deleted. + bool DeleteMap(string const & fileName); bool AddObserver(Observer & observer); @@ -251,7 +280,7 @@ public: FeaturesLoaderGuard(Index const & parent, MwmId id); inline MwmSet::MwmId GetId() const { return m_lock.GetId(); } - string GetCountryFileName() const; + string GetFileName() const; bool IsWorld() const; void GetFeature(uint32_t offset, FeatureType & ft); diff --git a/indexer/indexer_tests/index_builder_test.cpp b/indexer/indexer_tests/index_builder_test.cpp index 1ebfe9c068..7efeb27fb6 100644 --- a/indexer/indexer_tests/index_builder_test.cpp +++ b/indexer/indexer_tests/index_builder_test.cpp @@ -56,7 +56,7 @@ UNIT_TEST(BuildIndexTest) { // Check that index actually works. Index index; - UNUSED_VALUE(index.Register(platform::LocalCountryFile::MakeForTesting("build_index_test"))); + UNUSED_VALUE(index.Register(fileName)); // Make sure that index is actually parsed. NoopFunctor fn; diff --git a/indexer/indexer_tests/index_test.cpp b/indexer/indexer_tests/index_test.cpp index 1e24aa5365..dfea961b07 100644 --- a/indexer/indexer_tests/index_test.cpp +++ b/indexer/indexer_tests/index_test.cpp @@ -6,8 +6,6 @@ #include "coding/file_name_utils.hpp" #include "coding/internal/file_data.hpp" -#include "platform/country_file.hpp" -#include "platform/local_country_file.hpp" #include "platform/platform.hpp" #include "base/logging.hpp" @@ -18,11 +16,6 @@ #include "std/bind.hpp" #include "std/string.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; - -namespace -{ void CheckedDeleteFile(string const & file) { if (Platform::IsFileExistsByFullPath(file)) @@ -32,60 +25,57 @@ void CheckedDeleteFile(string const & file) class Observer : public Index::Observer { public: - Observer() : m_numRegisteredCalls(0), m_numDeregisteredCalls(0) {} - - ~Observer() { CheckExpectations(); } - - void ExpectRegisteredMap(platform::LocalCountryFile const & localFile) + Observer(string const & file) + : m_file(file), + m_map_registered_calls(0), + m_map_update_is_ready_calls(0), + m_map_updated_calls(0), + m_map_deleted_calls(0) { - m_expectedRegisteredMaps.push_back(localFile); } - void ExpectDeregisteredMap(platform::LocalCountryFile const & localFile) + // Index::Observer overrides: + void OnMapRegistered(string const & file) override { - m_expectedDeregisteredMaps.push_back(localFile); + CHECK_EQUAL(m_file, file, ()); + ++m_map_registered_calls; } - void CheckExpectations() + void OnMapUpdateIsReady(string const & file) override { - CHECK_EQUAL(m_numRegisteredCalls, m_expectedRegisteredMaps.size(), ()); - CHECK_EQUAL(m_numDeregisteredCalls, m_expectedDeregisteredMaps.size(), ()); + CHECK_EQUAL(m_file, file, ()); + ++m_map_update_is_ready_calls; } - // Index::Observer overrides: - void OnMapRegistered(platform::LocalCountryFile const & localFile) override + void OnMapUpdated(string const & file) override { - CHECK_LESS(m_numRegisteredCalls, m_expectedRegisteredMaps.size(), - ("Unexpected OnMapRegistered() call (", m_numRegisteredCalls, "): ", localFile)); - CHECK_EQUAL(m_expectedRegisteredMaps[m_numRegisteredCalls], localFile, (m_numRegisteredCalls)); - ++m_numRegisteredCalls; + CHECK_EQUAL(m_file, file, ()); + ++m_map_updated_calls; } - void OnMapDeregistered(platform::LocalCountryFile const & localFile) override + void OnMapDeleted(string const & file) override { - CHECK_LESS(m_numDeregisteredCalls, m_expectedDeregisteredMaps.size(), - ("Unexpected OnMapDeregistered() call (", m_numDeregisteredCalls, "): ", localFile)); - CHECK_EQUAL(m_expectedDeregisteredMaps[m_numDeregisteredCalls], localFile, - (m_numDeregisteredCalls)); - ++m_numDeregisteredCalls; + CHECK_EQUAL(m_file, file, ()); + ++m_map_deleted_calls; } - inline size_t MapRegisteredCalls() const { return m_numRegisteredCalls; } - inline size_t MapDeregisteredCalls() const { return m_numDeregisteredCalls; } + int map_registered_calls() const { return m_map_registered_calls; } + int map_update_is_ready_calls() const { return m_map_update_is_ready_calls; } + int map_updated_calls() const { return m_map_updated_calls; } + int map_deleted_calls() const { return m_map_deleted_calls; } private: - size_t m_numRegisteredCalls; - size_t m_numDeregisteredCalls; - - vector<LocalCountryFile> m_expectedRegisteredMaps; - vector<LocalCountryFile> m_expectedDeregisteredMaps; + string const m_file; + int m_map_registered_calls; + int m_map_update_is_ready_calls; + int m_map_updated_calls; + int m_map_deleted_calls; }; -} // namespace UNIT_TEST(Index_Parse) { Index index; - UNUSED_VALUE(index.RegisterMap(platform::LocalCountryFile::MakeForTesting("minsk-pass"))); + UNUSED_VALUE(index.RegisterMap("minsk-pass" DATA_FILE_EXTENSION)); // Make sure that index is actually parsed. NoopFunctor fn; @@ -94,68 +84,65 @@ UNIT_TEST(Index_Parse) UNIT_TEST(Index_MwmStatusNotifications) { - Platform & platform = GetPlatform(); - string const mapsDir = GetPlatform().WritableDir(); - CountryFile const countryFile("minsk-pass"); + string const resourcesDir = GetPlatform().ResourcesDir(); + string const sourceMapName = "minsk-pass" DATA_FILE_EXTENSION; + string const sourceMapPath = my::JoinFoldersToPath(resourcesDir, sourceMapName); + string const testMapName = "minsk-pass-copy" DATA_FILE_EXTENSION; + string const testMapPath = my::JoinFoldersToPath(resourcesDir, testMapName); + string const testMapUpdatePath = testMapPath + READY_FILE_EXTENSION; - // These two classes point to the same file, but will be considered - // by Index as distinct files because versions are artificially set - // to different numbers. - LocalCountryFile const localFileV1(mapsDir, countryFile, 1 /* version */); - LocalCountryFile const localFileV2(mapsDir, countryFile, 2 /* version */); + TEST(my::CopyFileX(sourceMapPath, testMapPath), ()); + MY_SCOPE_GUARD(testMapGuard, bind(&CheckedDeleteFile, testMapPath)); Index index; - Observer observer; + Observer observer(testMapName); index.AddObserver(observer); - TEST_EQUAL(0, observer.MapRegisteredCalls(), ()); - - MwmSet::MwmId localFileV1Id; + TEST_EQUAL(0, observer.map_registered_calls(), ()); // Checks that observers are triggered after map registration. { - observer.ExpectRegisteredMap(localFileV1); - pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(localFileV1); + pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(testMapName); TEST(p.first.IsLocked(), ()); TEST(p.second, ()); - observer.CheckExpectations(); - localFileV1Id = p.first.GetId(); + TEST_EQUAL(1, observer.map_registered_calls(), ()); } - // Checks that map can't registered twice. + // Checks that map can't registered twice and observers aren't + // triggered. { - pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(localFileV1); + pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(testMapName); TEST(p.first.IsLocked(), ()); TEST(!p.second, ()); - observer.CheckExpectations(); - TEST_EQUAL(localFileV1Id, p.first.GetId(), ()); + TEST_EQUAL(1, observer.map_registered_calls(), ()); } - // Checks that observers are notified when map is updated. - MwmSet::MwmId localFileV2Id; + TEST(my::CopyFileX(testMapPath, testMapUpdatePath), ()); + MY_SCOPE_GUARD(testMapUpdateGuard, bind(&CheckedDeleteFile, testMapUpdatePath)); + + // Checks that observers are notified when map is deleted. { - observer.ExpectRegisteredMap(localFileV2); - observer.ExpectDeregisteredMap(localFileV1); - pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(localFileV2); + TEST_EQUAL(0, observer.map_update_is_ready_calls(), ()); + TEST_EQUAL(0, observer.map_updated_calls(), ()); + pair<MwmSet::MwmLock, Index::UpdateStatus> const p = index.UpdateMap(testMapName); TEST(p.first.IsLocked(), ()); - TEST(p.second, ()); - observer.CheckExpectations(); - localFileV2Id = p.first.GetId(); - TEST_NOT_EQUAL(localFileV1Id, localFileV2Id, ()); + TEST_EQUAL(Index::UPDATE_STATUS_OK, p.second, ()); + TEST_EQUAL(1, observer.map_update_is_ready_calls(), ()); + TEST_EQUAL(1, observer.map_updated_calls(), ()); } - // Tries to deregister a map in presence of an active lock. Map - // should be marked "to be removed" but can't be deregistered. After - // leaving the inner block the map should be deregistered. + // Tries to delete map in presence of active lock. Map should be + // marked "to be removed" but can't be deleted. { - MwmSet::MwmLock const lock = index.GetMwmLockByCountryFile(countryFile); + MwmSet::MwmLock const lock = index.GetMwmLockByFileName(testMapName); TEST(lock.IsLocked(), ()); - TEST(!index.DeregisterMap(countryFile), ()); - observer.CheckExpectations(); - - observer.ExpectDeregisteredMap(localFileV2); + TEST(!index.DeleteMap(testMapName), ()); + TEST_EQUAL(0, observer.map_deleted_calls(), ()); } - observer.CheckExpectations(); + + // Checks that observers are notified when all locks are destroyed. + TEST_EQUAL(1, observer.map_deleted_calls(), ()); + index.RemoveObserver(observer); } diff --git a/indexer/indexer_tests/mwm_set_test.cpp b/indexer/indexer_tests/mwm_set_test.cpp index 30b9adebe5..27fd148f6b 100644 --- a/indexer/indexer_tests/mwm_set_test.cpp +++ b/indexer/indexer_tests/mwm_set_test.cpp @@ -7,11 +7,6 @@ #include "std/initializer_list.hpp" #include "std/unordered_map.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; - -using TMwmsInfo = unordered_map<string, shared_ptr<MwmInfo>>; - namespace { class MwmValue : public MwmSet::MwmValueBase @@ -21,17 +16,16 @@ class MwmValue : public MwmSet::MwmValueBase class TestMwmSet : public MwmSet { protected: - // MwmSet overrides: - bool GetVersion(LocalCountryFile const & localFile, MwmInfo & info) const override + bool GetVersion(string const & path, MwmInfo & info) const override { - int const n = localFile.GetCountryFile().GetNameWithoutExt()[0] - '0'; + int const n = path[0] - '0'; info.m_maxScale = n; info.m_limitRect = m2::RectD(0, 0, 1, 1); info.m_version.format = version::lastFormat; return true; } - TMwmValueBasePtr CreateValue(LocalCountryFile const &) const override + TMwmValueBasePtr CreateValue(string const &) const override { return TMwmValueBasePtr(new MwmValue()); } @@ -40,21 +34,23 @@ public: ~TestMwmSet() { Cleanup(); } }; -void GetMwmsInfo(MwmSet const & mwmSet, TMwmsInfo & mwmsInfo) +void GetMwmsInfo(MwmSet const & mwmSet, + unordered_map<MwmSet::TMwmFileName, shared_ptr<MwmInfo>> & mwmsInfo) { vector<shared_ptr<MwmInfo>> mwmsInfoList; mwmSet.GetMwmsInfo(mwmsInfoList); mwmsInfo.clear(); for (shared_ptr<MwmInfo> const & info : mwmsInfoList) - mwmsInfo[info->GetCountryName()] = info; + mwmsInfo[info->GetFileName()] = info; } -void TestFilesPresence(TMwmsInfo const & mwmsInfo, initializer_list<string> const & expectedNames) +void TestFilesPresence(unordered_map<MwmSet::TMwmFileName, shared_ptr<MwmInfo>> const & mwmsInfo, + initializer_list<MwmSet::TMwmFileName> const & expectedNames) { TEST_EQUAL(expectedNames.size(), mwmsInfo.size(), ()); - for (string const & countryFileName : expectedNames) - TEST_EQUAL(1, mwmsInfo.count(countryFileName), (countryFileName)); + for (MwmSet::TMwmFileName const & fileName : expectedNames) + TEST_EQUAL(1, mwmsInfo.count(fileName), (fileName)); } } // namespace @@ -62,12 +58,12 @@ void TestFilesPresence(TMwmsInfo const & mwmsInfo, initializer_list<string> cons UNIT_TEST(MwmSetSmokeTest) { TestMwmSet mwmSet; - TMwmsInfo mwmsInfo; + unordered_map<MwmSet::TMwmFileName, shared_ptr<MwmInfo>> mwmsInfo; - UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("0"))); - UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("1"))); - UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("2"))); - mwmSet.Deregister(CountryFile("1")); + UNUSED_VALUE(mwmSet.Register("0")); + UNUSED_VALUE(mwmSet.Register("1")); + UNUSED_VALUE(mwmSet.Register("2")); + mwmSet.Deregister("1"); GetMwmsInfo(mwmSet, mwmsInfo); TestFilesPresence(mwmsInfo, {"0", "2"}); @@ -76,13 +72,13 @@ UNIT_TEST(MwmSetSmokeTest) TEST_EQUAL(mwmsInfo["0"]->m_maxScale, 0, ()); TEST(mwmsInfo["2"]->IsUpToDate(), ()); { - MwmSet::MwmLock const lock0 = mwmSet.GetMwmLockByCountryFile(CountryFile("0")); - MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByCountryFile(CountryFile("1")); + MwmSet::MwmLock const lock0 = mwmSet.GetMwmLockByFileName("0"); + MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByFileName("1"); TEST(lock0.IsLocked(), ()); TEST(!lock1.IsLocked(), ()); } - UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("3"))); + UNUSED_VALUE(mwmSet.Register("3")); GetMwmsInfo(mwmSet, mwmsInfo); TestFilesPresence(mwmsInfo, {"0", "2", "3"}); @@ -95,10 +91,10 @@ UNIT_TEST(MwmSetSmokeTest) TEST_EQUAL(mwmsInfo["3"]->m_maxScale, 3, ()); { - MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByCountryFile(CountryFile("1")); + MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByFileName("1"); TEST(!lock1.IsLocked(), ()); - mwmSet.Deregister(CountryFile("3")); - UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("4"))); + mwmSet.Deregister("3"); + UNUSED_VALUE(mwmSet.Register("4")); } GetMwmsInfo(mwmSet, mwmsInfo); @@ -111,7 +107,7 @@ UNIT_TEST(MwmSetSmokeTest) TEST(mwmsInfo["4"]->IsUpToDate(), ()); TEST_EQUAL(mwmsInfo["4"]->m_maxScale, 4, ()); - UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("5"))); + UNUSED_VALUE(mwmSet.Register("5")); GetMwmsInfo(mwmSet, mwmsInfo); TestFilesPresence(mwmsInfo, {"0", "2", "4", "5"}); @@ -130,17 +126,17 @@ UNIT_TEST(MwmSetSmokeTest) UNIT_TEST(MwmSetIdTest) { TestMwmSet mwmSet; - TEST(mwmSet.Register(LocalCountryFile::MakeForTesting("3")).second, ()); + TEST(mwmSet.Register("3").second, ()); - MwmSet::MwmId const id0 = mwmSet.GetMwmLockByCountryFile(CountryFile("3")).GetId(); - MwmSet::MwmId const id1 = mwmSet.GetMwmLockByCountryFile(CountryFile("3")).GetId(); + MwmSet::MwmId const id0 = mwmSet.GetMwmLockByFileName("3").GetId(); + MwmSet::MwmId const id1 = mwmSet.GetMwmLockByFileName("3").GetId(); TEST(id0.IsAlive(), ()); TEST(id1.IsAlive(), ()); TEST_EQUAL(id0.GetInfo().get(), id1.GetInfo().get(), ()); - TEST_EQUAL(MwmInfo::STATUS_REGISTERED, id0.GetInfo()->GetStatus(), ()); + TEST_EQUAL(MwmInfo::STATUS_UP_TO_DATE, id0.GetInfo()->GetStatus(), ()); - TEST(mwmSet.Deregister(CountryFile("3")), ()); + TEST(mwmSet.Deregister("3"), ()); // Test that both id's are sour now. TEST(!id0.IsAlive(), ()); @@ -155,15 +151,14 @@ UNIT_TEST(MwmSetLockAndIdTest) MwmSet::MwmId id; { - pair<MwmSet::MwmLock, bool> const lockFlag = - mwmSet.Register(LocalCountryFile::MakeForTesting("4")); + pair<MwmSet::MwmLock, bool> const lockFlag = mwmSet.Register("4"); MwmSet::MwmLock const & lock = lockFlag.first; bool const success = lockFlag.second; TEST(lock.IsLocked(), ()); TEST(success, ("Can't register test mwm 4")); - TEST_EQUAL(MwmInfo::STATUS_REGISTERED, lock.GetInfo()->GetStatus(), ()); + TEST_EQUAL(MwmInfo::STATUS_UP_TO_DATE, lock.GetInfo()->GetStatus(), ()); - TEST(!mwmSet.Deregister(CountryFile("4")), ()); // It's not possible to remove mwm 4 right now. + TEST(!mwmSet.Deregister("4"), ()); // It's not possible to remove mwm 4 right now. TEST(lock.IsLocked(), ()); TEST_EQUAL(MwmInfo::STATUS_MARKED_TO_DEREGISTER, lock.GetInfo()->GetStatus(), ()); id = lock.GetId(); @@ -177,7 +172,7 @@ UNIT_TEST(MwmSetLockAndIdTest) // It is not possible to lock mwm 4 because it is already deleted, // and it is not possible to get to it's info from mwmSet. - MwmSet::MwmLock lock = mwmSet.GetMwmLockByCountryFile(CountryFile("4")); + MwmSet::MwmLock lock = mwmSet.GetMwmLockByFileName("4"); TEST(!lock.IsLocked(), ()); TEST(!lock.GetId().IsAlive(), ()); TEST(!lock.GetId().GetInfo().get(), ()); diff --git a/indexer/mwm_set.cpp b/indexer/mwm_set.cpp index d6961ebdd0..c9005078ce 100644 --- a/indexer/mwm_set.cpp +++ b/indexer/mwm_set.cpp @@ -9,9 +9,6 @@ #include "std/algorithm.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; - MwmInfo::MwmInfo() : m_minScale(0), m_maxScale(0), m_status(STATUS_DEREGISTERED), m_lockCount(0) {} MwmInfo::MwmTypeT MwmInfo::GetType() const @@ -77,64 +74,57 @@ MwmSet::~MwmSet() void MwmSet::Cleanup() { lock_guard<mutex> lock(m_lock); + ClearCacheImpl(m_cache.begin(), m_cache.end()); + +#ifdef DEBUG + for (auto const & p : m_info) + { + MwmInfo const & info = *p.second; + if (info.IsUpToDate()) + { + ASSERT_EQUAL(info.m_lockCount, 0, (info.m_fileName)); + ASSERT(!info.m_fileName.empty(), ()); + } + } +#endif } -MwmSet::MwmId MwmSet::GetMwmIdByCountryFileImpl(CountryFile const & countryFile) const +MwmSet::MwmId MwmSet::GetMwmIdByFileNameImpl(TMwmFileName const & name) const { - string const name = countryFile.GetNameWithoutExt(); ASSERT(!name.empty(), ()); auto const it = m_info.find(name); - if (it == m_info.cend() || it->second.empty()) + if (it == m_info.cend()) return MwmId(); - return MwmId(it->second.back()); + return MwmId(it->second); } -pair<MwmSet::MwmLock, bool> MwmSet::Register(LocalCountryFile const & localFile) +pair<MwmSet::MwmLock, bool> MwmSet::Register(TMwmFileName const & fileName) { lock_guard<mutex> lock(m_lock); - CountryFile const & countryFile = localFile.GetCountryFile(); - MwmId const id = GetMwmIdByCountryFileImpl(countryFile); + MwmId const id = GetMwmIdByFileNameImpl(fileName); if (!id.IsAlive()) - return RegisterImpl(localFile); - + return RegisterImpl(fileName); shared_ptr<MwmInfo> info = id.GetInfo(); - - // Deregister old mwm for the country. - if (info->GetVersion() < localFile.GetVersion()) - { - DeregisterImpl(id); - return RegisterImpl(localFile); - } - - string const name = countryFile.GetNameWithoutExt(); - // Update the status of the mwm with the same version. - if (info->GetVersion() == localFile.GetVersion()) - { - LOG(LWARNING, ("Trying to add already registered mwm:", name)); - info->SetStatus(MwmInfo::STATUS_REGISTERED); - return make_pair(GetLock(id), false); - } - - LOG(LWARNING, ("Trying to add too old (", localFile.GetVersion(), ") mwm (", name, - "), current version:", info->GetVersion())); - return make_pair(MwmLock(), false); + if (info->IsRegistered()) + LOG(LWARNING, ("Trying to add already registered mwm:", fileName)); + else + info->SetStatus(MwmInfo::STATUS_UP_TO_DATE); + return make_pair(GetLock(id), false); } -pair<MwmSet::MwmLock, bool> MwmSet::RegisterImpl(LocalCountryFile const & localFile) +pair<MwmSet::MwmLock, bool> MwmSet::RegisterImpl(TMwmFileName const & fileName) { shared_ptr<MwmInfo> info(new MwmInfo()); // This function can throw an exception for a bad mwm file. - if (!GetVersion(localFile, *info)) + if (!GetVersion(fileName, *info)) return make_pair(MwmLock(), false); - info->SetStatus(MwmInfo::STATUS_REGISTERED); - info->m_file = localFile; - string const name = localFile.GetCountryFile().GetNameWithoutExt(); + info->SetStatus(MwmInfo::STATUS_UP_TO_DATE); + info->m_fileName = fileName; + m_info[fileName] = info; - vector<shared_ptr<MwmInfo>> & infos = m_info[name]; - infos.push_back(info); return make_pair(GetLock(MwmId(info)), true); } @@ -143,28 +133,26 @@ bool MwmSet::DeregisterImpl(MwmId const & id) if (!id.IsAlive()) return false; shared_ptr<MwmInfo> const & info = id.GetInfo(); - if (info->m_lockCount == 0) { info->SetStatus(MwmInfo::STATUS_DEREGISTERED); - vector<shared_ptr<MwmInfo>> & infos = m_info[info->GetCountryName()]; - infos.erase(remove(infos.begin(), infos.end(), info), infos.end()); - OnMwmDeregistered(info->GetLocalFile()); + m_info.erase(info->m_fileName); + OnMwmDeleted(info); return true; } info->SetStatus(MwmInfo::STATUS_MARKED_TO_DEREGISTER); return false; } -bool MwmSet::Deregister(CountryFile const & countryFile) +bool MwmSet::Deregister(TMwmFileName const & fileName) { lock_guard<mutex> lock(m_lock); - return DeregisterImpl(countryFile); + return DeregisterImpl(fileName); } -bool MwmSet::DeregisterImpl(CountryFile const & countryFile) +bool MwmSet::DeregisterImpl(TMwmFileName const & fileName) { - MwmId const id = GetMwmIdByCountryFileImpl(countryFile); + MwmId const id = GetMwmIdByFileNameImpl(fileName); if (!id.IsAlive()) return false; bool const deregistered = DeregisterImpl(id); @@ -176,24 +164,21 @@ void MwmSet::DeregisterAll() { lock_guard<mutex> lock(m_lock); - for (auto const & p : m_info) + for (auto it = m_info.begin(); it != m_info.end();) { - // Vector of shared pointers is copied here because an original - // vector will be modified by the body of the cycle. - vector<shared_ptr<MwmInfo>> infos = p.second; - for (shared_ptr<MwmInfo> info : infos) - DeregisterImpl(MwmId(info)); + auto cur = it++; + DeregisterImpl(MwmId(cur->second)); } // Do not call ClearCache - it's under mutex lock. ClearCacheImpl(m_cache.begin(), m_cache.end()); } -bool MwmSet::IsLoaded(CountryFile const & countryFile) const +bool MwmSet::IsLoaded(TMwmFileName const & fileName) const { lock_guard<mutex> lock(m_lock); - MwmId const id = GetMwmIdByCountryFileImpl(countryFile); + MwmId const id = GetMwmIdByFileNameImpl(fileName + DATA_FILE_EXTENSION); return id.IsAlive() && id.GetInfo()->IsRegistered(); } @@ -203,10 +188,7 @@ void MwmSet::GetMwmsInfo(vector<shared_ptr<MwmInfo>> & info) const info.clear(); info.reserve(m_info.size()); for (auto const & p : m_info) - { - if (!p.second.empty()) - info.push_back(p.second.back()); - } + info.push_back(p.second); } MwmSet::TMwmValueBasePtr MwmSet::LockValue(MwmId const & id) @@ -234,7 +216,7 @@ MwmSet::TMwmValueBasePtr MwmSet::LockValueImpl(MwmId const & id) return result; } } - return CreateValue(info->GetLocalFile()); + return CreateValue(info->m_fileName); } void MwmSet::UnlockValue(MwmId const & id, TMwmValueBasePtr p) @@ -251,10 +233,22 @@ void MwmSet::UnlockValueImpl(MwmId const & id, TMwmValueBasePtr p) return; shared_ptr<MwmInfo> const & info = id.GetInfo(); - ASSERT_GREATER(info->m_lockCount, 0, ()); + CHECK_GREATER(info->m_lockCount, 0, ()); --info->m_lockCount; - if (info->m_lockCount == 0 && info->GetStatus() == MwmInfo::STATUS_MARKED_TO_DEREGISTER) - VERIFY(DeregisterImpl(id), ()); + if (info->m_lockCount == 0) + { + switch (info->GetStatus()) + { + case MwmInfo::STATUS_MARKED_TO_DEREGISTER: + CHECK(DeregisterImpl(id), ()); + break; + case MwmInfo::STATUS_PENDING_UPDATE: + OnMwmReadyForUpdate(info); + break; + default: + break; + } + } if (info->IsUpToDate()) { @@ -273,20 +267,20 @@ void MwmSet::ClearCache() ClearCacheImpl(m_cache.begin(), m_cache.end()); } -MwmSet::MwmId MwmSet::GetMwmIdByCountryFile(CountryFile const & countryFile) const +MwmSet::MwmId MwmSet::GetMwmIdByFileName(TMwmFileName const & fileName) const { lock_guard<mutex> lock(m_lock); - MwmId const id = GetMwmIdByCountryFileImpl(countryFile); - ASSERT(id.IsAlive(), ("Can't get an mwm's (", countryFile.GetNameWithoutExt(), ") identifier.")); + MwmId const id = GetMwmIdByFileNameImpl(fileName); + ASSERT(id.IsAlive(), ("Can't get an mwm's (", fileName, ") identifier.")); return id; } -MwmSet::MwmLock MwmSet::GetMwmLockByCountryFile(CountryFile const & countryFile) +MwmSet::MwmLock MwmSet::GetMwmLockByFileName(TMwmFileName const & fileName) { lock_guard<mutex> lock(m_lock); - MwmId const id = GetMwmIdByCountryFileImpl(countryFile); + MwmId const id = GetMwmIdByFileNameImpl(fileName); TMwmValueBasePtr value(nullptr); if (id.IsAlive()) value = LockValueImpl(id); diff --git a/indexer/mwm_set.hpp b/indexer/mwm_set.hpp index dfc225f4c4..25682c16b0 100644 --- a/indexer/mwm_set.hpp +++ b/indexer/mwm_set.hpp @@ -2,9 +2,6 @@ #include "indexer/mwm_version.hpp" -#include "platform/country_file.hpp" -#include "platform/local_country_file.hpp" - #include "geometry/rect2d.hpp" #include "base/macros.hpp" @@ -34,9 +31,10 @@ public: enum Status { - STATUS_REGISTERED, ///< Mwm is registered and up to date. - STATUS_MARKED_TO_DEREGISTER, ///< Mwm is marked to be deregistered as soon as possible. - STATUS_DEREGISTERED, ///< Mwm is deregistered. + STATUS_UP_TO_DATE, ///< Mwm is registered and up-to-date + STATUS_MARKED_TO_DEREGISTER, ///< Mwm is marked to be deregistered as soon as possible + STATUS_DEREGISTERED, ///< Mwm is deregistered + STATUS_PENDING_UPDATE ///< Mwm is registered but there're a pending update to it }; MwmInfo(); @@ -48,32 +46,31 @@ public: inline Status GetStatus() const { return m_status; } - inline bool IsUpToDate() const { return IsRegistered(); } - inline bool IsRegistered() const { - return m_status == STATUS_REGISTERED; + return m_status == STATUS_UP_TO_DATE || m_status == STATUS_PENDING_UPDATE; } - inline platform::LocalCountryFile const & GetLocalFile() const { return m_file; } - - inline string GetCountryName() const { return m_file.GetCountryFile().GetNameWithoutExt(); } + inline bool IsUpToDate() const { return m_status == STATUS_UP_TO_DATE; } - inline int64_t GetVersion() const { return m_file.GetVersion(); } + inline string const & GetFileName() const { return m_fileName; } MwmTypeT GetType() const; private: inline void SetStatus(Status status) { m_status = status; } - platform::LocalCountryFile m_file; ///< Path to the mwm file. - Status m_status; ///< Current country status. - uint8_t m_lockCount; ///< Number of locks. + string m_fileName; ///< Path to the mwm file. + Status m_status; ///< Current country status. + uint8_t m_lockCount; ///< Number of locks. }; class MwmSet { public: + using TMwmFileName = string; + using TMwmInfoTable = map<TMwmFileName, shared_ptr<MwmInfo>>; + struct MwmId { public: @@ -97,9 +94,9 @@ public: friend ostream & operator<<(ostream & os, MwmId const & id) { if (id.m_info.get()) - os << "MwmId [" << id.m_info->GetCountryName() << "]"; + os << "MwmId[" << id.m_info->GetFileName() << "]"; else - os << "MwmId [invalid]"; + os << "MwmId[invalid]"; return os; } @@ -155,43 +152,41 @@ public: /// Registers a new map. /// - /// \return A pair of an MwmLock and a flag. There are three cases: - /// * the map is newer than the newest registered - returns - /// active lock and set flag. - /// * the map is older than the newest registered - returns inactive lock and - /// unset flag. - /// * the version of the map equals to the version of the newest registered - - /// returns active lock and unset flag. + /// \return A pair of an MwmLock and a flag. MwmLock is locked iff the + /// map with fileName was created or already exists. Flag + /// is set when the map was registered for a first + /// time. Thus, there are three main cases: /// - /// *NOTE* When a new version for the same country is registered, - /// all previous versions will be automatically deregistered. + /// * the map already exists - returns active lock and unset flag + /// * the map was already registered - returns active lock and set flag + /// * the map can't be registered - returns inactive lock and unset flag + //@{ protected: - WARN_UNUSED_RESULT pair<MwmLock, bool> RegisterImpl(platform::LocalCountryFile const & localFile); + WARN_UNUSED_RESULT pair<MwmLock, bool> RegisterImpl(TMwmFileName const & fileName); public: - WARN_UNUSED_RESULT pair<MwmLock, bool> Register(platform::LocalCountryFile const & localFile); + WARN_UNUSED_RESULT pair<MwmLock, bool> Register(TMwmFileName const & fileName); //@} /// @name Remove mwm. //@{ protected: - /// Deregisters a map from internal records. + /// Deregisters a map from the set when it's possible. Note that an + /// underlying file is not deleted. /// - /// \param countryFile A countryFile denoting a map to be deregistered. - /// \return True if the map was successfully deregistered. If map is locked - /// now, returns false. + /// @return true when the map was deregistered. //@{ bool DeregisterImpl(MwmId const & id); - bool DeregisterImpl(platform::CountryFile const & countryFile); + bool DeregisterImpl(TMwmFileName const & ofileName); //@} public: - bool Deregister(platform::CountryFile const & countryFile); + bool Deregister(TMwmFileName const & fileName); void DeregisterAll(); //@} - /// Returns true when country is registered and can be used. - bool IsLoaded(platform::CountryFile const & countryFile) const; + /// @param[in] file File name without extension. + bool IsLoaded(TMwmFileName const & fileName) const; /// Get ids of all mwms. Some of them may be with not active status. /// In that case, LockValue returns NULL. @@ -199,14 +194,14 @@ public: void ClearCache(); - MwmId GetMwmIdByCountryFile(platform::CountryFile const & countryFile) const; + MwmId GetMwmIdByFileName(TMwmFileName const & fileName) const; - MwmLock GetMwmLockByCountryFile(platform::CountryFile const & countryFile); + MwmLock GetMwmLockByFileName(TMwmFileName const & fileName); protected: /// @return True when file format version was successfully read to MwmInfo. - virtual bool GetVersion(platform::LocalCountryFile const & localFile, MwmInfo & info) const = 0; - virtual TMwmValueBasePtr CreateValue(platform::LocalCountryFile const & localFile) const = 0; + virtual bool GetVersion(TMwmFileName const & fileName, MwmInfo & info) const = 0; + virtual TMwmValueBasePtr CreateValue(string const & name) const = 0; void Cleanup(); @@ -231,7 +226,7 @@ protected: /// Find mwm with a given name. /// @precondition This function is always called under mutex m_lock. - MwmId GetMwmIdByCountryFileImpl(platform::CountryFile const & countryFile) const; + MwmId GetMwmIdByFileNameImpl(TMwmFileName const & fileName) const; /// @precondition This function is always called under mutex m_lock. WARN_UNUSED_RESULT inline MwmLock GetLock(MwmId const & id) @@ -241,9 +236,12 @@ protected: // This method is called under m_lock when mwm is removed from a // registry. - virtual void OnMwmDeregistered(platform::LocalCountryFile const & localFile) {} + virtual void OnMwmDeleted(shared_ptr<MwmInfo> const & info) {} + + // This method is called under m_lock when mwm is ready for update. + virtual void OnMwmReadyForUpdate(shared_ptr<MwmInfo> const & info) {} - map<string, vector<shared_ptr<MwmInfo>>> m_info; + TMwmInfoTable m_info; mutable mutex m_lock; }; diff --git a/integration_tests/osrm_test_tools.cpp b/integration_tests/osrm_test_tools.cpp index 4bf6cd94b8..90f9dbeaa9 100644 --- a/integration_tests/osrm_test_tools.cpp +++ b/integration_tests/osrm_test_tools.cpp @@ -11,8 +11,6 @@ #include "map/feature_vec_model.hpp" -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" #include "platform/platform.hpp" #include "platform/preferred_languages.hpp" @@ -22,7 +20,6 @@ using namespace routing; -using platform::LocalCountryFile; namespace { @@ -37,19 +34,19 @@ namespace namespace integration { - shared_ptr<model::FeaturesFetcher> CreateFeaturesFetcher(vector<LocalCountryFile> const & localFiles) + shared_ptr<model::FeaturesFetcher> CreateFeaturesFetcher(vector<string> const & mapNames) { size_t const maxOpenFileNumber = 1024; ChangeMaxNumberOfOpenFiles(maxOpenFileNumber); shared_ptr<model::FeaturesFetcher> featuresFetcher(new model::FeaturesFetcher); featuresFetcher->InitClassificator(); - for (LocalCountryFile const & localFile : localFiles) + for (auto const mapName : mapNames) { - pair<MwmSet::MwmLock, bool> result = featuresFetcher->RegisterMap(localFile); + pair<MwmSet::MwmLock, bool> result = featuresFetcher->RegisterMap(mapName); if (!result.second) { - ASSERT(false, ("Can't register", localFile)); + ASSERT(false, ()); return nullptr; } } @@ -85,27 +82,21 @@ namespace integration ASSERT(featuresFetcher, ()); ASSERT(searchEngine, ()); - shared_ptr<OsrmRouter> osrmRouter(new OsrmRouter( - &featuresFetcher->GetIndex(), [searchEngine](m2::PointD const & pt) - { - return searchEngine->GetCountryFile(pt); - }, - [](string const & countryFileName) - { - return make_shared<LocalCountryFile>(LocalCountryFile::MakeForTesting(countryFileName)); - })); + shared_ptr<OsrmRouter> osrmRouter(new OsrmRouter(&featuresFetcher->GetIndex(), + [searchEngine](m2::PointD const & pt) + { + return searchEngine->GetCountryFile(pt); + })); return osrmRouter; } class OsrmRouterComponents { public: - OsrmRouterComponents(vector<LocalCountryFile> const & localFiles) - : m_featuresFetcher(CreateFeaturesFetcher(localFiles)), - m_searchEngine(CreateSearchEngine(m_featuresFetcher)), - m_osrmRouter(CreateOsrmRouter(m_featuresFetcher, m_searchEngine)) - { - } + OsrmRouterComponents(vector<string> const & mapNames) + : m_featuresFetcher(CreateFeaturesFetcher(mapNames)), + m_searchEngine(CreateSearchEngine(m_featuresFetcher)), + m_osrmRouter(CreateOsrmRouter(m_featuresFetcher, m_searchEngine)) {} OsrmRouter * GetOsrmRouter() const { return m_osrmRouter.get(); } search::Engine * GetSearchEngine() const { return m_searchEngine.get(); } @@ -115,17 +106,28 @@ namespace integration shared_ptr<OsrmRouter> m_osrmRouter; }; - shared_ptr<OsrmRouterComponents> LoadMaps(vector<LocalCountryFile> const & localFiles) + void GetMapNames(vector<string> & maps) + { + Platform const & pl = GetPlatform(); + + pl.GetFilesByExt(pl.ResourcesDir(), DATA_FILE_EXTENSION, maps); + pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps); + + sort(maps.begin(), maps.end()); + maps.erase(unique(maps.begin(), maps.end()), maps.end()); + } + + shared_ptr<OsrmRouterComponents> LoadMaps(vector<string> const & mapNames) { - return shared_ptr<OsrmRouterComponents>(new OsrmRouterComponents(localFiles)); + return shared_ptr<OsrmRouterComponents>(new OsrmRouterComponents(mapNames)); } shared_ptr<OsrmRouterComponents> LoadAllMaps() { - vector<LocalCountryFile> localFiles; - platform::FindAllLocalMaps(localFiles); - ASSERT(!localFiles.empty(), ()); - return LoadMaps(localFiles); + vector<string> maps; + GetMapNames(maps); + ASSERT(!maps.empty(), ()); + return LoadMaps(maps); } OsrmRouterComponents & GetAllMaps() diff --git a/integration_tests/osrm_test_tools.hpp b/integration_tests/osrm_test_tools.hpp index b6d23146d7..8bc5608e7a 100644 --- a/integration_tests/osrm_test_tools.hpp +++ b/integration_tests/osrm_test_tools.hpp @@ -8,8 +8,6 @@ #include "routing/osrm_router.hpp" -#include "platform/local_country_file.hpp" - /* * These tests are developed to simplify routing integration tests writing. * You can use the interface bellow however you want but there are some hints. @@ -48,7 +46,7 @@ namespace integration OsrmRouterComponents & routerComponents); OsrmRouterComponents & GetAllMaps(); - shared_ptr<OsrmRouterComponents> LoadMaps(vector<platform::LocalCountryFile> const & localFiles); + shared_ptr<OsrmRouterComponents> LoadMaps(vector<string> const & mapNames); TRouteResult CalculateRoute(OsrmRouterComponents const & routerComponents, m2::PointD const & startPoint, m2::PointD const & startDirection, m2::PointD const & finalPoint); diff --git a/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm b/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm index c1ff8c6a9c..567183be8d 100644 --- a/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm +++ b/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm @@ -100,4 +100,4 @@ extern UIColor * const kActiveDownloaderViewColor; self.downloadButton.minY = self.notNowButton.frame.origin.y; } -@end +@end
\ No newline at end of file diff --git a/map/active_maps_layout.cpp b/map/active_maps_layout.cpp index 090cef36b5..8dc200ded3 100644 --- a/map/active_maps_layout.cpp +++ b/map/active_maps_layout.cpp @@ -36,14 +36,14 @@ ActiveMapsLayout::~ActiveMapsLayout() #endif } -void ActiveMapsLayout::Init(vector<platform::CountryFile> const & files) +void ActiveMapsLayout::Init(vector<string> const & maps) { Clear(); Storage & storage = GetStorage(); - for (auto const & file : files) + for (auto const & file : maps) { - vector<TIndex> arr = storage.FindAllIndexesByFile(file.GetNameWithoutExt()); + vector<TIndex> arr = storage.FindAllIndexesByFile(Storage::MapWithoutExt(file)); if (!arr.empty()) { TStatus status; @@ -53,9 +53,7 @@ void ActiveMapsLayout::Init(vector<platform::CountryFile> const & files) m_items.push_back({ arr, status, options, options }); } else - { LOG(LWARNING, ("Can't find map index for", file)); - } } auto const comparatorFn = [&storage] (Item const & lhs, Item const & rhs) @@ -239,7 +237,7 @@ LocalAndRemoteSizeT const ActiveMapsLayout::GetRemoteCountrySizes(TGroup const & LocalAndRemoteSizeT const ActiveMapsLayout::GetRemoteCountrySizes(TIndex const & index) const { - platform::CountryFile const & c = GetStorage().CountryByIndex(index).GetFile(); + CountryFile const & c = GetStorage().CountryByIndex(index).GetFile(); size_t const mapSize = c.GetRemoteSize(TMapOptions::EMap); return { mapSize, c.GetRemoteSize(TMapOptions::ECarRouting) }; } @@ -267,7 +265,7 @@ void ActiveMapsLayout::DownloadMap(TIndex const & index, TMapOptions const & opt else { Storage const & s = GetStorage(); - vector<TIndex> arr = s.FindAllIndexesByFile(s.GetCountryFile(index).GetNameWithoutExt()); + vector<TIndex> arr = s.FindAllIndexesByFile(s.CountryFileNameWithoutExt(index)); int position = InsertInGroup(TGroup::ENewMap, { arr, TStatus::ENotDownloaded, validOptions, validOptions }); NotifyInsertion(TGroup::ENewMap, position); } diff --git a/map/active_maps_layout.hpp b/map/active_maps_layout.hpp index 331d17296b..27c1e101e4 100644 --- a/map/active_maps_layout.hpp +++ b/map/active_maps_layout.hpp @@ -1,10 +1,9 @@ #pragma once -#include "storage/index.hpp" #include "storage/storage_defines.hpp" +#include "storage/index.hpp" #include "platform/country_defines.hpp" -#include "platform/country_file.hpp" #include "base/buffer_vector.hpp" @@ -96,7 +95,7 @@ private: Storage const & GetStorage() const; Storage & GetStorage(); - void Init(vector<platform::CountryFile> const & files); + void Init(vector<string> const & maps); void Clear(); void ShowMap(TIndex const & index); diff --git a/map/benchmark_engine.cpp b/map/benchmark_engine.cpp index 208cd1bb94..3c99a0b9f9 100644 --- a/map/benchmark_engine.cpp +++ b/map/benchmark_engine.cpp @@ -133,11 +133,8 @@ void BenchmarkEngine::PrepareMaps() // add only maps needed for benchmarks MapsCollector collector; ForEachBenchmarkRecord(collector); - for (string const & map : collector.m_maps) - { - LOG(LINFO, ("Looking for:", map)); - m_framework->RegisterMap(platform::LocalCountryFile::MakeForTesting(map)); - } + for_each(collector.m_maps.begin(), collector.m_maps.end(), + bind(&Framework::RegisterMap, m_framework, _1)); } BenchmarkEngine::BenchmarkEngine(Framework * fw) diff --git a/map/benchmark_tool/features_loading.cpp b/map/benchmark_tool/features_loading.cpp index a316188916..c9fd84ab7d 100644 --- a/map/benchmark_tool/features_loading.cpp +++ b/map/benchmark_tool/features_loading.cpp @@ -9,8 +9,6 @@ #include "platform/platform.hpp" -#include "coding/file_name_utils.hpp" - #include "base/macros.hpp" #include "base/timer.hpp" @@ -99,20 +97,8 @@ namespace void RunFeaturesLoadingBenchmark(string const & file, pair<int, int> scaleR, AllResult & res) { - string baseName = file; - my::GetNameFromFullPath(baseName); - - // Check that file is relative to maps dir. - ASSERT_EQUAL(file, baseName, ()); - - string countryFileName = baseName; - my::GetNameWithoutExt(countryFileName); - - platform::LocalCountryFile localFile = - platform::LocalCountryFile::MakeForTesting(countryFileName); - feature::DataHeader header; - LoadMapHeader(GetPlatform().GetCountryReader(localFile, TMapOptions::EMap), header); + LoadMapHeader(GetPlatform().GetReader(file), header); pair<int, int> const r = header.GetScaleRange(); if (r.first > scaleR.first) @@ -124,7 +110,7 @@ void RunFeaturesLoadingBenchmark(string const & file, pair<int, int> scaleR, All return; model::FeaturesFetcher src; - UNUSED_VALUE(src.RegisterMap(platform::LocalCountryFile::MakeForTesting(countryFileName))); + UNUSED_VALUE(src.RegisterMap(file)); RunBenchmark(src, header.GetBounds(), scaleR, res); } diff --git a/map/country_tree.cpp b/map/country_tree.cpp index 4d62070703..e0c53bccd2 100644 --- a/map/country_tree.cpp +++ b/map/country_tree.cpp @@ -65,7 +65,7 @@ CountryTree & CountryTree::operator=(CountryTree const & other) return *this; } -void CountryTree::Init(vector<platform::CountryFile> const & maps) +void CountryTree::Init(vector<string> const & maps) { ASSERT(IsValid(), ()); m_layout->Init(maps); diff --git a/map/country_tree.hpp b/map/country_tree.hpp index 2a28dce7a3..ab8e88838a 100644 --- a/map/country_tree.hpp +++ b/map/country_tree.hpp @@ -5,8 +5,6 @@ #include "storage/index.hpp" #include "storage/storage_defines.hpp" -#include "platform/country_file.hpp" - #include "base/buffer_vector.hpp" #include "std/string.hpp" @@ -38,7 +36,7 @@ public: CountryTree & operator=(CountryTree const & other); /// @param[in] Sorted vector of current .mwm files. - void Init(vector<platform::CountryFile> const & maps); + void Init(vector<string> const & maps); void Clear(); ActiveMapsLayout & GetActiveMapLayout(); diff --git a/map/feature_vec_model.cpp b/map/feature_vec_model.cpp index ca5f1f4ba0..ec7b701f25 100644 --- a/map/feature_vec_model.cpp +++ b/map/feature_vec_model.cpp @@ -13,20 +13,9 @@ #include "std/bind.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; namespace model { -FeaturesFetcher::FeaturesFetcher() -{ - m_multiIndex.AddObserver(*this); -} - -FeaturesFetcher::~FeaturesFetcher() -{ - m_multiIndex.RemoveObserver(*this); -} // While reading any files (classificator or mwm), there are 2 types of possible exceptions: // Reader::Exception, FileAbsentException. @@ -44,47 +33,71 @@ void FeaturesFetcher::InitClassificator() } } -pair<MwmSet::MwmLock, bool> FeaturesFetcher::RegisterMap(LocalCountryFile const & localFile) +pair<MwmSet::MwmLock, bool> FeaturesFetcher::RegisterMap(string const & file) { - string const countryFileName = localFile.GetCountryFile().GetNameWithoutExt(); try { - pair<MwmSet::MwmLock, bool> result = m_multiIndex.RegisterMap(localFile); - if (!result.second) + pair<MwmSet::MwmLock, bool> p = m_multiIndex.RegisterMap(file); + if (!p.second) { - LOG(LWARNING, ("Can't add map", countryFileName, - "Probably it's already added or has newer data version.")); - return result; + LOG(LWARNING, + ("Can't add map", file, "Probably it's already added or has newer data version.")); + return p; } - MwmSet::MwmLock & lock = result.first; + MwmSet::MwmLock & lock = p.first; ASSERT(lock.IsLocked(), ("Mwm lock invariant violation.")); m_rect.Add(lock.GetInfo()->m_limitRect); - return result; + return p; } catch (RootException const & e) { - LOG(LERROR, ("IO error while adding ", countryFileName, " map. ", e.what())); + LOG(LERROR, ("IO error while adding ", file, " map. ", e.what())); return make_pair(MwmSet::MwmLock(), false); } } -bool FeaturesFetcher::DeregisterMap(CountryFile const & countryFile) +void FeaturesFetcher::DeregisterMap(string const & file) { m_multiIndex.Deregister(file); } + +void FeaturesFetcher::DeregisterAllMaps() { m_multiIndex.DeregisterAll(); } + +bool FeaturesFetcher::DeleteMap(string const & file) +{ + return m_multiIndex.DeleteMap(file); +} + +pair<MwmSet::MwmLock, Index::UpdateStatus> FeaturesFetcher::UpdateMap(string const & file) { - return m_multiIndex.Deregister(countryFile); + return m_multiIndex.UpdateMap(file); } -void FeaturesFetcher::DeregisterAllMaps() { m_multiIndex.DeregisterAll(); } +//void FeaturesFetcher::Clean() +//{ +// m_rect.MakeEmpty(); +// // TODO: m_multiIndex.Clear(); - is it needed? +//} void FeaturesFetcher::ClearCaches() { m_multiIndex.ClearCache(); } -void FeaturesFetcher::OnMapDeregistered(platform::LocalCountryFile const & localFile) +/* +bool FeaturesFetcher::IsLoaded(m2::PointD const & pt) const { - if (m_onMapDeregistered) - m_onMapDeregistered(localFile); + vector<MwmInfo> info; + m_multiIndex.GetMwmInfo(info); + + for (size_t i = 0; i < info.size(); ++i) + if (info[i].IsExist() && + info[i].GetType() == MwmInfo::COUNTRY && + info[i].m_limitRect.IsPointInside(pt)) + { + return true; + } + + return false; } +*/ m2::RectD FeaturesFetcher::GetWorldRect() const { diff --git a/map/feature_vec_model.hpp b/map/feature_vec_model.hpp index 9698d5a745..b671ba0721 100644 --- a/map/feature_vec_model.hpp +++ b/map/feature_vec_model.hpp @@ -15,7 +15,7 @@ namespace model { //#define USE_BUFFER_READER -class FeaturesFetcher : public Index::Observer + class FeaturesFetcher { public: #ifdef USE_BUFFER_READER @@ -24,56 +24,58 @@ class FeaturesFetcher : public Index::Observer typedef ModelReaderPtr ReaderT; #endif - typedef function<void(platform::LocalCountryFile const &)> TMapDeregisteredCallback; - private: m2::RectD m_rect; Index m_multiIndex; - TMapDeregisteredCallback m_onMapDeregistered; - public: - FeaturesFetcher(); - - virtual ~FeaturesFetcher(); - void InitClassificator(); - inline void SetOnMapDeregisteredCallback(TMapDeregisteredCallback const & callback) - { - m_onMapDeregistered = callback; - } - /// Registers a new map. /// - /// \return A pair of an MwmLock and a flag. There are three cases: - /// * the map is newer than the newest registered - returns - /// active lock and set flag - /// * the map is older than the newest registered - returns inactive lock and - /// unset flag. - /// * the version of the map equals to the version of the newest registered - - /// returns active lock and unset flag. - WARN_UNUSED_RESULT pair<MwmSet::MwmLock, bool> RegisterMap( - platform::LocalCountryFile const & localFile); + /// \return A pair of an MwmLock and a flag. MwmLock is locked iff the + /// map with fileName was created or already exists. Flag + /// is set when the map was registered for a first + /// time. Thus, there are three main cases: + /// + /// * the map already exists - returns active lock and unset flag + /// * the map was already registered - returns active lock and set flag + /// * the map can't be registered - returns inactive lock and unset flag + WARN_UNUSED_RESULT pair<MwmSet::MwmLock, bool> RegisterMap(string const & file); /// Deregisters a map denoted by file from internal records. - bool DeregisterMap(platform::CountryFile const & countryFile); + void DeregisterMap(string const & file); /// Deregisters all registered maps. void DeregisterAllMaps(); + /// Deletes all files related to map denoted by file. + /// + /// \return True if a map was successfully deleted. + bool DeleteMap(string const & file); + + /// Replaces a map file corresponding to fileName with a new one, when + /// it's possible - no clients of the map file. Otherwise, update + /// will be delayed. + /// + /// \return * the map file have been updated - returns active lock and + /// UPDATE_STATUS_OK + /// * update is delayed because the map is busy - returns active lock and + /// UPDATE_STATUS_UPDATE_DELAYED + /// * the file isn't suitable for update - returns inactive lock and + /// UPDATE_STATUS_BAD_FILE + WARN_UNUSED_RESULT pair<MwmSet::MwmLock, Index::UpdateStatus> UpdateMap(string const & file); + //@} + //void Clean(); void ClearCaches(); - inline bool IsLoaded(string const & countryFileName) const + inline bool IsLoaded(string const & fName) const { - return m_multiIndex.IsLoaded(platform::CountryFile(countryFileName)); + return m_multiIndex.IsLoaded(fName); } - // Index::Observer overrides: - void OnMapDeregistered(platform::LocalCountryFile const & localFile) override; - //bool IsLoaded(m2::PointD const & pt) const; /// @name Features enumeration. diff --git a/map/framework.cpp b/map/framework.cpp index e4083f8004..9265215902 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -44,11 +44,10 @@ #include "gui/controller.hpp" -#include "platform/local_country_file_utils.hpp" #include "platform/measurement_utils.hpp" -#include "platform/platform.hpp" -#include "platform/preferred_languages.hpp" #include "platform/settings.hpp" +#include "platform/preferred_languages.hpp" +#include "platform/platform.hpp" #include "coding/internal/file_data.hpp" #include "coding/zip_reader.hpp" @@ -82,8 +81,6 @@ using namespace storage; using namespace routing; using namespace location; -using platform::CountryFile; -using platform::LocalCountryFile; #ifdef FIXED_LOCATION Framework::FixedPosition::FixedPosition() @@ -98,20 +95,38 @@ namespace static const int BM_TOUCH_PIXEL_INCREASE = 20; } -pair<MwmSet::MwmLock, bool> Framework::RegisterMap(LocalCountryFile const & localFile) +pair<MwmSet::MwmLock, bool> Framework::RegisterMap(string const & file) { - string const countryFileName = localFile.GetCountryFile().GetNameWithoutExt(); - LOG(LINFO, ("Loading map:", countryFileName)); - return m_model.RegisterMap(localFile); + LOG(LINFO, ("Loading map:", file)); + + pair<MwmSet::MwmLock, bool> p = m_model.RegisterMap(file); + if (!p.second) + return p; + MwmSet::MwmLock const & lock = p.first; + ASSERT(lock.IsLocked(), ()); + + shared_ptr<MwmInfo> info = lock.GetInfo(); + ASSERT(info, ()); + + if (info->m_version.format == version::v1) + { + // Now we do force delete of old (April 2011) maps. + LOG(LINFO, ("Deleting old map:", file)); + + DeregisterMap(file); + VERIFY(my::DeleteFileX(GetPlatform().WritablePathForFile(file)), ()); + return make_pair(MwmSet::MwmLock(), false); + } + + return p; } -void Framework::DeregisterMap(CountryFile const & countryFile) +void Framework::DeregisterMap(string const & file) { m_model.DeregisterMap(file); } + +void Framework::OnLocationError(TLocationError /*error*/) { - m_model.DeregisterMap(countryFile); } -void Framework::OnLocationError(TLocationError /*error*/) {} - void Framework::OnLocationUpdate(GpsInfo const & info) { #ifdef FIXED_LOCATION @@ -183,6 +198,32 @@ m2::PointD Framework::GetWidgetSize(InformationDisplay::WidgetType widget) const return m_informationDisplay.GetWidgetSize(widget); } +void Framework::GetMaps(vector<string> & maps) const +{ + Platform & pl = GetPlatform(); + + pl.GetFilesByExt(pl.ResourcesDir(), DATA_FILE_EXTENSION, maps); + pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps); + + // Remove duplicate maps if they're both present in Resources and in Writable dirs. + sort(maps.begin(), maps.end()); + maps.erase(unique(maps.begin(), maps.end()), maps.end()); + +#ifdef OMIM_OS_ANDROID + // On Android World and WorldCoasts can be stored in alternative /Android/obb/ path. + char const * arrCheck[] = { WORLD_FILE_NAME DATA_FILE_EXTENSION, + WORLD_COASTS_FILE_NAME DATA_FILE_EXTENSION }; + + for (size_t i = 0; i < ARRAY_SIZE(arrCheck); ++i) + { + auto const it = lower_bound(maps.begin(), maps.end(), arrCheck[i]); + if (it == maps.end() || *it != arrCheck[i]) + maps.insert(it, arrCheck[i]); + } +#endif +} + + Framework::Framework() : m_navigator(m_scales), m_animator(this), @@ -239,7 +280,6 @@ Framework::Framework() #endif m_model.InitClassificator(); - m_model.SetOnMapDeregisteredCallback(bind(&Framework::OnMapDeregistered, this, _1)); LOG(LDEBUG, ("Classificator initialized")); // To avoid possible races - init search engine once in constructor. @@ -252,7 +292,7 @@ Framework::Framework() LOG(LDEBUG, ("Maps initialized")); // Init storage with needed callback. - m_storage.Init(bind(&Framework::UpdateAfterDownload, this, _1)); + m_storage.Init(bind(&Framework::UpdateAfterDownload, this, _1, _2)); LOG(LDEBUG, ("Storage initialized")); #ifdef USE_PEDESTRIAN_ROUTER @@ -268,7 +308,6 @@ Framework::Framework() Framework::~Framework() { delete m_benchmarkEngine; - m_model.SetOnMapDeregisteredCallback(nullptr); } void Framework::DrawSingleFrame(m2::PointD const & center, int zoomModifier, @@ -356,34 +395,44 @@ double Framework::GetVisualScale() const return m_scales.GetVisualScale(); } -void Framework::DeleteCountry(storage::TIndex const & index, TMapOptions opt) +void Framework::DeleteCountry(TIndex const & index, TMapOptions opt) { - switch (opt) + if (HasOptions(opt, TMapOptions::EMap)) + opt = TMapOptions::EMapWithCarRouting; + + if (!m_storage.DeleteFromDownloader(index)) { - case TMapOptions::ENothing: - return; - case TMapOptions::EMap: // fall through - case TMapOptions::EMapWithCarRouting: + CountryFile const & file = m_storage.CountryByIndex(index).GetFile(); + + if (HasOptions(opt, TMapOptions::EMap)) { - CountryFile const & countryFile = m_storage.GetCountryFile(index); - // m_model will notify us when latest map file will be deleted via - // OnMapDeregistered call. - if (m_model.DeregisterMap(countryFile)) - { - InvalidateRect(GetCountryBounds(countryFile.GetNameWithoutExt()), true /* doForceUpdate */); - } - // TODO (@ldragunov, @gorshenin): rewrite routing session to use MwmLocks. Thus, - // it won' be needed to reset it after maps update. - m_routingSession.Reset(); - return; + if (m_model.DeleteMap(file.GetFileWithExt(TMapOptions::EMap))) + InvalidateRect(GetCountryBounds(file.GetFileWithoutExt()), true); } - case TMapOptions::ECarRouting: - m_routingSession.Reset(); - m_storage.DeleteCountry(index, opt); - return; + + if (HasOptions(opt, TMapOptions::ECarRouting)) + m_routingSession.DeleteIndexFile(file.GetFileWithExt(TMapOptions::ECarRouting)); + + m_storage.NotifyStatusChanged(index); + + DeleteCountryIndexes(m_storage.CountryFileNameWithoutExt(index)); } } +void Framework::DeleteCountryIndexes(string const & mwmName) +{ + m_routingSession.Reset(); + + Platform::FilesList files; + Platform const & pl = GetPlatform(); + string const path = pl.WritablePathForCountryIndexes(mwmName); + + /// @todo We need correct regexp for any file (not including "." and ".."). + pl.GetFilesByRegExp(path, mwmName + "\\..*", files); + for (auto const & file : files) + (void) my::DeleteFileX(path + file); +} + void Framework::DownloadCountry(TIndex const & index, TMapOptions opt) { m_storage.DownloadCountry(index, opt); @@ -410,8 +459,7 @@ m2::RectD Framework::GetCountryBounds(string const & file) const m2::RectD Framework::GetCountryBounds(TIndex const & index) const { - CountryFile const & file = m_storage.GetCountryFile(index); - return GetCountryBounds(file.GetNameWithoutExt()); + return GetCountryBounds(m_storage.CountryFileNameWithoutExt(index)); } void Framework::ShowCountry(TIndex const & index) @@ -421,57 +469,72 @@ void Framework::ShowCountry(TIndex const & index) ShowRectEx(GetCountryBounds(index)); } -void Framework::UpdateAfterDownload(LocalCountryFile const & localFile) +void Framework::UpdateAfterDownload(string const & fileName, TMapOptions opt) { - // TODO (@ldragunov, @gorshenin): rewrite routing session to use MwmLocks. Thus, - // it won' be needed to reset it after maps update. - m_routingSession.Reset(); + if (HasOptions(opt, TMapOptions::EMap)) + { + // Delete old (splitted) map files, if any. + char const * arr[] = { "Japan", "Brazil" }; + for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) + if (fileName.find(arr[i]) == 0) + { + if (m_model.DeleteMap(string(arr[i]) + DATA_FILE_EXTENSION)) + Invalidate(true); - if (!HasOptions(localFile.GetFiles(), TMapOptions::EMap)) - return; + // Routing index doesn't exist for this map files. + } - // Add downloaded map. - pair<MwmSet::MwmLock, bool> const result = m_model.RegisterMap(localFile); - MwmSet::MwmLock const & lock = result.first; - if (lock.IsLocked()) - InvalidateRect(lock.GetInfo()->m_limitRect, true /* doForceUpdate */); - GetSearchEngine()->ClearViewportsCache(); -} + // Add downloaded map. + pair<MwmSet::MwmLock, Index::UpdateStatus> const p = m_model.UpdateMap(fileName); + if (p.second == Index::UPDATE_STATUS_OK) + { + MwmSet::MwmLock const & lock = p.first; + ASSERT(lock.IsLocked(), ()); + InvalidateRect(lock.GetInfo()->m_limitRect, true); + } -void Framework::OnMapDeregistered(platform::LocalCountryFile const & localFile) -{ - m_storage.DeleteCustomCountryVersion(localFile); + GetSearchEngine()->ClearViewportsCache(); + } + + // Replace routing file. + if (HasOptions(opt, TMapOptions::ECarRouting)) + { + string routingName = fileName + ROUTING_FILE_EXTENSION; + m_routingSession.DeleteIndexFile(routingName); + + routingName = GetPlatform().WritableDir() + routingName; + VERIFY(my::RenameFileX(routingName + READY_FILE_EXTENSION, routingName), ()); + } + + string countryName(fileName); + my::GetNameWithoutExt(countryName); + DeleteCountryIndexes(countryName); } void Framework::RegisterAllMaps() { - ASSERT(!m_storage.IsDownloadInProgress(), - ("Registering maps while map downloading leads to removing downloading maps from " - "ActiveMapsListener::m_items.")); - - platform::CleanupMapsDirectory(); - m_storage.RegisterAllLocalMaps(); + ASSERT(!Storage().IsDownloadInProgress(), + ("Registering maps while map downloading leads to removing downloading maps from ActiveMapsListener::m_items.")); + //ASSERT(m_model.IsEmpty(), ()); - int minFormat = numeric_limits<int>::max(); - vector<CountryFile> maps; - m_storage.GetLocalMaps(maps); + int minVersion = numeric_limits<int>::max(); - for (CountryFile const & countryFile : maps) + vector<string> maps; + GetMaps(maps); + for_each(maps.begin(), maps.end(), [&](string const & file) { - shared_ptr<LocalCountryFile> localFile = m_storage.GetLatestLocalFile(countryFile); - if (!localFile) - continue; - pair<MwmSet::MwmLock, bool> const p = RegisterMap(*localFile); - if (!p.second) - continue; - MwmSet::MwmLock const & lock = p.first; - ASSERT(lock.IsLocked(), ()); - minFormat = min(minFormat, static_cast<int>(lock.GetInfo()->m_version.format)); - } + pair<MwmSet::MwmLock, bool> const p = RegisterMap(file); + if (p.second) + { + MwmSet::MwmLock const & lock = p.first; + ASSERT(lock.IsLocked(), ()); + minVersion = min(minVersion, static_cast<int>(lock.GetInfo()->m_version.format)); + } + }); m_countryTree.Init(maps); - GetSearchEngine()->SupportOldFormat(minFormat < version::v3); + GetSearchEngine()->SupportOldFormat(minVersion < version::v3); } void Framework::DeregisterAllMaps() @@ -2149,27 +2212,22 @@ void Framework::SetRouter(RouterType type) alohalytics::LogEvent("Routing_CalculatingRoute", statistics); }; - auto countryFileGetter = [this](m2::PointD const & p) -> string - { - // TODO (@gorshenin): fix search engine to return CountryFile - // instances instead of plain strings. - return GetSearchEngine()->GetCountryFile(p); - }; - auto localFileGetter = [this](string const & countryFile) -> shared_ptr<LocalCountryFile> - { - return m_storage.GetLatestLocalFile(CountryFile(countryFile)); - }; - unique_ptr<IRouter> router; if (type == RouterType::Pedestrian) { - router = CreatePedestrianAStarBidirectionalRouter(m_model.GetIndex(), countryFileGetter, - routingVisualizerFn); + auto const countryFileFn = [this](m2::PointD const & pt) + { + return GetSearchEngine()->GetCountryFile(pt) + DATA_FILE_EXTENSION; + }; + router = CreatePedestrianAStarBidirectionalRouter(m_model.GetIndex(), countryFileFn, routingVisualizerFn); } else { - router.reset(new OsrmRouter(&m_model.GetIndex(), countryFileGetter, localFileGetter, - routingVisualizerFn)); + auto const countryFileFn = [this](m2::PointD const & pt) + { + return GetSearchEngine()->GetCountryFile(pt); + }; + router.reset(new OsrmRouter(&m_model.GetIndex(), countryFileFn, routingVisualizerFn)); } m_routingSession.SetRouter(move(router), routingStatisticsFn); diff --git a/map/framework.hpp b/map/framework.hpp index 89f0541bda..d0e6a723b2 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -135,10 +135,8 @@ protected: static const int TOUCH_PIXEL_RADIUS = 20; /// This function is called by m_storage to notify that country downloading is finished. - void UpdateAfterDownload(platform::LocalCountryFile const & localFile); - - /// This function is called by m_model when the map file is deregistered. - void OnMapDeregistered(platform::LocalCountryFile const & localFile); + /// @param[in] file Country file name (without extensions). + void UpdateAfterDownload(string const & file, TMapOptions opt); //my::Timer m_timer; inline double ElapsedSeconds() const @@ -157,7 +155,10 @@ protected: void ClearAllCaches(); - void DeregisterMap(platform::CountryFile const & countryFile); + void DeregisterMap(string const & file); + + /// Deletes user calculated indexes on country updates + void DeleteCountryIndexes(string const & mwmName); public: Framework(); @@ -188,6 +189,11 @@ public: void ReleaseSingleFrameRenderer(); bool IsSingleFrameRendererInited() const; + /// @name Process storage connecting/disconnecting. + //@{ + /// @param[out] maps File names without path. + void GetMaps(vector<string> & maps) const; + /// Registers all local map files in internal indexes. void RegisterAllMaps(); @@ -198,7 +204,7 @@ public: /// /// @return True and inner mwm data version from header in version /// or false in case of errors. - pair<MwmSet::MwmLock, bool> RegisterMap(platform::LocalCountryFile const & localFile); + pair<MwmSet::MwmLock, bool> RegisterMap(string const & file); //@} /// Deletes all disk files corresponding to country. diff --git a/map/map_tests/bookmarks_test.cpp b/map/map_tests/bookmarks_test.cpp index 51cc6e854b..8edd6d69f6 100644 --- a/map/map_tests/bookmarks_test.cpp +++ b/map/map_tests/bookmarks_test.cpp @@ -400,7 +400,7 @@ UNIT_TEST(Bookmarks_AddressInfo) // Maps added in constructor (we need minsk-pass.mwm only) Framework fm; fm.DeregisterAllMaps(); - fm.RegisterMap(platform::LocalCountryFile::MakeForTesting("minsk-pass")); + fm.RegisterMap("minsk-pass.mwm"); fm.OnSize(800, 600); // assume that developers have English or Russian system language :) diff --git a/map/mwm_tests/multithread_mwm_test.cpp b/map/mwm_tests/multithread_mwm_test.cpp index 974cb436a4..22529e5752 100644 --- a/map/mwm_tests/multithread_mwm_test.cpp +++ b/map/mwm_tests/multithread_mwm_test.cpp @@ -63,7 +63,7 @@ namespace SourceT src; src.InitClassificator(); - UNUSED_VALUE(src.RegisterMap(platform::LocalCountryFile::MakeForTesting(file))); + UNUSED_VALUE(src.RegisterMap(file + DATA_FILE_EXTENSION)); // Check that country rect is valid and not infinity. m2::RectD const r = src.GetWorldRect(); diff --git a/map/mwm_tests/mwm_foreach_test.cpp b/map/mwm_tests/mwm_foreach_test.cpp index ce23dc7eea..6036885f89 100644 --- a/map/mwm_tests/mwm_foreach_test.cpp +++ b/map/mwm_tests/mwm_foreach_test.cpp @@ -247,18 +247,17 @@ public: } }; -void RunTest(string const & countryFileName) +void RunTest(string const & file) { model::FeaturesFetcher src1; src1.InitClassificator(); - platform::LocalCountryFile localFile(platform::LocalCountryFile::MakeForTesting(countryFileName)); - UNUSED_VALUE(src1.RegisterMap(localFile)); + UNUSED_VALUE(src1.RegisterMap(file)); vector<m2::RectD> rects; rects.push_back(src1.GetWorldRect()); - ModelReaderPtr reader = GetPlatform().GetCountryReader(localFile, TMapOptions::EMap); + ModelReaderPtr reader = GetPlatform().GetReader(file); while (!rects.empty()) { @@ -302,10 +301,15 @@ void RunTest(string const & countryFileName) } } +void RunTestForChoice(string const & fName) +{ + RunTest(fName + DATA_FILE_EXTENSION); +} + } UNIT_TEST(ForEach_QueryResults) { - RunTest("minsk-pass"); + RunTestForChoice("minsk-pass"); //RunTestForChoice("london-center"); } diff --git a/map/mwm_tests/mwm_index_test.cpp b/map/mwm_tests/mwm_index_test.cpp index 700d1ddf12..5f3b3e509e 100644 --- a/map/mwm_tests/mwm_index_test.cpp +++ b/map/mwm_tests/mwm_index_test.cpp @@ -36,11 +36,10 @@ public: } }; -bool RunTest(string const & countryFileName, int lowS, int highS) +bool RunTest(string const & fileName, int lowS, int highS) { model::FeaturesFetcher src; - pair<MwmSet::MwmLock, bool> const p = - src.RegisterMap(platform::LocalCountryFile::MakeForTesting(countryFileName)); + pair<MwmSet::MwmLock, bool> const p = src.RegisterMap(fileName); if (!p.second) return false; MwmSet::MwmLock const & lock = p.first; @@ -67,8 +66,8 @@ UNIT_TEST(ForEachFeatureID_Test) classificator::Load(); /// @todo Uncomment World* checking after next map data update. - // TEST(RunTest("World", 0, scales::GetUpperWorldScale()), ()); - // TEST(RunTest("WorldCoasts.mwm", 0, scales::GetUpperWorldScale()), ()); - // TEST(RunTest("Belarus", scales::GetUpperWorldScale() + 1, scales::GetUpperStyleScale()), ()); - TEST(RunTest("minsk-pass", scales::GetUpperWorldScale() + 1, scales::GetUpperStyleScale()), ()); + //TEST(RunTest("World.mwm", 0, scales::GetUpperWorldScale()), ()); + //TEST(RunTest("WorldCoasts.mwm", 0, scales::GetUpperWorldScale()), ()); + //TEST(RunTest("Belarus.mwm", scales::GetUpperWorldScale() + 1, scales::GetUpperStyleScale()), ()); + TEST(RunTest("minsk-pass.mwm", scales::GetUpperWorldScale() + 1, scales::GetUpperStyleScale()), ()); } diff --git a/map/routing_session.cpp b/map/routing_session.cpp index 431f13ee00..64aa286261 100644 --- a/map/routing_session.cpp +++ b/map/routing_session.cpp @@ -8,10 +8,12 @@ #include "coding/internal/file_data.hpp" + using namespace location; namespace routing { + static int const ON_ROUTE_MISSED_COUNT = 5; RoutingSession::RoutingSession() @@ -44,7 +46,7 @@ void RoutingSession::RebuildRoute(m2::PointD const & startPoint, TReadyCallbackF DoReadyCallback(*this, callback, m_routeSessionMutex)); } -void RoutingSession::DoReadyCallback::operator()(Route & route, IRouter::ResultCode e) +void RoutingSession::DoReadyCallback::operator() (Route & route, IRouter::ResultCode e) { threads::MutexGuard guard(m_routeSessionMutexInner); UNUSED_VALUE(guard); @@ -65,8 +67,6 @@ void RoutingSession::Reset() threads::MutexGuard guard(m_routeSessionMutex); UNUSED_VALUE(guard); Route(string()).Swap(m_route); - - m_router->ClearState(); } RoutingSession::State RoutingSession::OnLocationPositionChanged(m2::PointD const & position, @@ -196,8 +196,14 @@ void RoutingSession::SetRouter(unique_ptr<IRouter> && router, TRoutingStatistics m_router.reset(new AsyncRouter(move(router), routingStatisticsFn)); } -void RoutingSession::MatchLocationToRoute(location::GpsInfo & location, - location::RouteMatchingInfo & routeMatchingInfo) const +void RoutingSession::DeleteIndexFile(string const & fileName) +{ + Reset(); + m_router->ClearState(); + (void) my::DeleteFileX(GetPlatform().WritablePathForFile(fileName)); +} + +void RoutingSession::MatchLocationToRoute(location::GpsInfo & location, location::RouteMatchingInfo & routeMatchingInfo) const { if (m_state != State::OnRoute) return; @@ -206,4 +212,5 @@ void RoutingSession::MatchLocationToRoute(location::GpsInfo & location, UNUSED_VALUE(guard); m_route.MatchLocationToRoute(location, routeMatchingInfo); } + } diff --git a/map/routing_session.hpp b/map/routing_session.hpp index 98a7606ae3..fd1abdb910 100644 --- a/map/routing_session.hpp +++ b/map/routing_session.hpp @@ -13,25 +13,24 @@ #include "base/mutex.hpp" -namespace location -{ -class RouteMatchingInfo; -} + +namespace location { class RouteMatchingInfo;} namespace routing { + class RoutingSession { public: enum State { RoutingNotActive, - RouteBuilding, // we requested a route and wait when it will be builded - RouteNotReady, // routing was not build - RouteNotStarted, // route is builded but the user isn't on it - OnRoute, // user follows the route - RouteNeedRebuild, // user left the route - RouteFinished // destination point is reached but the session isn't closed + RouteBuilding, // we requested a route and wait when it will be builded + RouteNotReady, // routing was not build + RouteNotStarted, // route is builded but the user isn't on it + OnRoute, // user follows the route + RouteNeedRebuild, // user left the route + RouteFinished // destination point is reached but the session isn't closed }; /* @@ -48,7 +47,7 @@ public: typedef function<void(map<string, string> const &)> TRoutingStatisticsCallback; - typedef function<void(Route const &, IRouter::ResultCode)> TReadyCallbackFn; + typedef function<void (Route const &, IRouter::ResultCode)> TReadyCallbackFn; RoutingSession(); @@ -56,8 +55,7 @@ public: TRoutingStatisticsCallback const & routingStatisticsFn); /// @param[in] startPoint and endPoint in mercator - void BuildRoute(m2::PointD const & startPoint, m2::PointD const & endPoint, - TReadyCallbackFn const & callback); + void BuildRoute(m2::PointD const & startPoint, m2::PointD const & endPoint, TReadyCallbackFn const & callback); void RebuildRoute(m2::PointD const & startPoint, TReadyCallbackFn const & callback); m2::PointD GetEndPoint() const { return m_endPoint; } @@ -70,8 +68,8 @@ public: State OnLocationPositionChanged(m2::PointD const & position, location::GpsInfo const & info); void GetRouteFollowingInfo(location::FollowingInfo & info) const; - void MatchLocationToRoute(location::GpsInfo & location, - location::RouteMatchingInfo & routeMatchingInfo) const; + void DeleteIndexFile(string const & fileName); + void MatchLocationToRoute(location::GpsInfo & location, location::RouteMatchingInfo & routeMatchingInfo) const; // TODO (Dragunov) Make activation of the pedestrian routing void ActivateAdditionalFeatures() {} @@ -83,13 +81,12 @@ private: TReadyCallbackFn m_callback; threads::Mutex & m_routeSessionMutexInner; - DoReadyCallback(RoutingSession & rs, TReadyCallbackFn const & cb, - threads::Mutex & routeSessionMutex) - : m_rs(rs), m_callback(cb), m_routeSessionMutexInner(routeSessionMutex) + DoReadyCallback(RoutingSession & rs, TReadyCallbackFn const & cb, threads::Mutex & routeSessionMutex) + : m_rs(rs), m_callback(cb), m_routeSessionMutexInner(routeSessionMutex) { } - void operator()(Route & route, IRouter::ResultCode e); + void operator() (Route & route, IRouter::ResultCode e); }; void AssignRoute(Route & route); @@ -106,4 +103,5 @@ private: int m_moveAwayCounter; m2::PointD m_lastGoodPosition; }; + } diff --git a/pedestrian_routing_benchmarks/pedestrian_routing_benchmarks.cpp b/pedestrian_routing_benchmarks/pedestrian_routing_benchmarks.cpp index fe9e956d73..3cffe31eaa 100644 --- a/pedestrian_routing_benchmarks/pedestrian_routing_benchmarks.cpp +++ b/pedestrian_routing_benchmarks/pedestrian_routing_benchmarks.cpp @@ -17,13 +17,11 @@ #include "std/utility.hpp" #include "std/vector.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; - namespace { string const MAP_NAME = "UK_England"; +string const MAP_FILE = MAP_NAME + DATA_FILE_EXTENSION; // Since for test purposes we compare routes lengths to check algorithms consistency, // we should use simplified pedestrian model, where all available edges have max speed @@ -71,7 +69,7 @@ m2::PointD GetPointOnEdge(routing::Edge & e, double posAlong) void GetNearestPedestrianEdges(Index & index, m2::PointD const & pt, vector<pair<routing::Edge, m2::PointD>> & edges) { - MwmSet::MwmId const id = index.GetMwmIdByCountryFile(CountryFile(MAP_NAME)); + MwmSet::MwmId const id = index.GetMwmIdByFileName(MAP_FILE); TEST(id.IsAlive(), ()); routing::PedestrianModel const vehicleModel; @@ -109,7 +107,7 @@ void TestRouter(routing::IRouter & router, m2::PointD const & startPos, m2::Poin void TestRouters(Index const & index, m2::PointD const & startPos, m2::PointD const & finalPos) { - auto const countryFileFn = [](m2::PointD const & /* point */) { return MAP_NAME; }; + auto const countryFileFn = [](m2::PointD const & /* point */){ return MAP_FILE; }; // find route by A*-bidirectional algorithm routing::Route routeFoundByAstarBidirectional(""); @@ -129,14 +127,9 @@ void TestTwoPointsOnFeature(m2::PointD const & startPos, m2::PointD const & fina { classificator::Load(); - CountryFile countryFile(MAP_NAME); - LocalCountryFile localFile = LocalCountryFile::MakeForTesting(MAP_NAME); - Index index; - UNUSED_VALUE(index.RegisterMap(localFile)); - TEST(index.IsLoaded(countryFile), ()); - MwmSet::MwmId const id = index.GetMwmIdByCountryFile(countryFile); - TEST(id.IsAlive(), ()); + UNUSED_VALUE(index.RegisterMap(MAP_FILE)); + TEST(index.IsLoaded(MAP_NAME), ()); vector<pair<routing::Edge, m2::PointD>> startEdges; GetNearestPedestrianEdges(index, startPos, startEdges); @@ -146,10 +139,8 @@ void TestTwoPointsOnFeature(m2::PointD const & startPos, m2::PointD const & fina GetNearestPedestrianEdges(index, finalPos, finalEdges); TEST(!finalEdges.empty(), ()); - m2::PointD const startPosOnFeature = - GetPointOnEdge(startEdges.front().first, 0.0 /* the start point of the feature */); - m2::PointD const finalPosOnFeature = - GetPointOnEdge(finalEdges.front().first, 1.0 /* the end point of the feature */); + m2::PointD const startPosOnFeature = GetPointOnEdge(startEdges.front().first, 0.0 /* the start point of the feature */ ); + m2::PointD const finalPosOnFeature = GetPointOnEdge(finalEdges.front().first, 1.0 /* the end point of the feature */ ); TestRouters(index, startPosOnFeature, finalPosOnFeature); } @@ -158,13 +149,11 @@ void TestTwoPoints(m2::PointD const & startPos, m2::PointD const & finalPos) { classificator::Load(); - CountryFile countryFile(MAP_NAME); - LocalCountryFile localFile = LocalCountryFile::MakeForTesting(MAP_NAME); - Index index; - UNUSED_VALUE(index.RegisterMap(localFile)); - TEST(index.IsLoaded(countryFile), ()); - MwmSet::MwmId const id = index.GetMwmIdByCountryFile(countryFile); + UNUSED_VALUE(index.RegisterMap(MAP_FILE)); + TEST(index.IsLoaded(MAP_NAME), ()); + + MwmSet::MwmId const id = index.GetMwmIdByFileName(MAP_FILE); TEST(id.IsAlive(), ()); TestRouters(index, startPos, finalPos); diff --git a/platform/country_defines.cpp b/platform/country_defines.cpp index 927f883709..5a3ab9e8f5 100644 --- a/platform/country_defines.cpp +++ b/platform/country_defines.cpp @@ -2,25 +2,14 @@ #include "base/assert.hpp" -bool HasOptions(TMapOptions mask, TMapOptions options) +bool HasOptions(TMapOptions options, TMapOptions bits) { - return (static_cast<uint8_t>(mask) & static_cast<uint8_t>(options)) == - static_cast<uint8_t>(options); + return (static_cast<uint8_t>(options) & static_cast<uint8_t>(bits)) == static_cast<uint8_t>(bits); } -TMapOptions SetOptions(TMapOptions mask, TMapOptions options) +TMapOptions SetOptions(TMapOptions options, TMapOptions bits) { - return static_cast<TMapOptions>(static_cast<uint8_t>(mask) | static_cast<uint8_t>(options)); -} - -TMapOptions UnsetOptions(TMapOptions mask, TMapOptions options) -{ - return static_cast<TMapOptions>(static_cast<uint8_t>(mask) & ~static_cast<uint8_t>(options)); -} - -TMapOptions LeastSignificantOption(TMapOptions mask) -{ - return static_cast<TMapOptions>(static_cast<uint8_t>(mask) & -static_cast<uint8_t>(mask)); + return static_cast<TMapOptions>(static_cast<uint8_t>(options) | static_cast<uint8_t>(bits)); } string DebugPrint(TMapOptions options) @@ -35,5 +24,8 @@ string DebugPrint(TMapOptions options) return "CarRouting"; case TMapOptions::EMapWithCarRouting: return "MapWithCarRouting"; + default: + ASSERT(false, ("Unknown TMapOptions (", static_cast<uint8_t>(options), ")")); + return string(); } } diff --git a/platform/country_defines.hpp b/platform/country_defines.hpp index 5c010cbd13..11e6f97842 100644 --- a/platform/country_defines.hpp +++ b/platform/country_defines.hpp @@ -10,12 +10,8 @@ enum class TMapOptions : uint8_t EMapWithCarRouting = 0x3 }; -bool HasOptions(TMapOptions mask, TMapOptions options); +bool HasOptions(TMapOptions options, TMapOptions bits); -TMapOptions SetOptions(TMapOptions mask, TMapOptions options); - -TMapOptions UnsetOptions(TMapOptions mask, TMapOptions options); - -TMapOptions LeastSignificantOption(TMapOptions mask); +TMapOptions SetOptions(TMapOptions options, TMapOptions bits); string DebugPrint(TMapOptions options); diff --git a/platform/country_file.cpp b/platform/country_file.cpp index b7f4210e8b..8fffb2a52d 100644 --- a/platform/country_file.cpp +++ b/platform/country_file.cpp @@ -22,8 +22,8 @@ string CountryFile::GetNameWithExt(TMapOptions file) const return m_name + DATA_FILE_EXTENSION + ROUTING_FILE_EXTENSION; default: ASSERT(false, ("Can't get name for:", file)); - return string(); } + return string(); } void CountryFile::SetRemoteSizes(uint32_t mapSize, uint32_t routingSize) diff --git a/platform/local_country_file.cpp b/platform/local_country_file.cpp index 2ccf776392..b730395ad5 100644 --- a/platform/local_country_file.cpp +++ b/platform/local_country_file.cpp @@ -34,23 +34,20 @@ void LocalCountryFile::SyncWithDisk() Platform & platform = GetPlatform(); - if (platform.GetFileSizeByFullPath(GetPath(TMapOptions::EMap), m_mapSize)) + if (platform.GetFileSizeByName(GetPath(TMapOptions::EMap), m_mapSize)) m_files = SetOptions(m_files, TMapOptions::EMap); string const routingPath = GetPath(TMapOptions::ECarRouting); - if (platform.GetFileSizeByFullPath(routingPath, m_routingSize)) + if (platform.GetFileSizeByName(routingPath, m_routingSize)) m_files = SetOptions(m_files, TMapOptions::ECarRouting); } -void LocalCountryFile::DeleteFromDisk(TMapOptions files) const +void LocalCountryFile::DeleteFromDisk() { for (TMapOptions file : {TMapOptions::EMap, TMapOptions::ECarRouting}) { - if (OnDisk(file) && HasOptions(files, file)) - { - if (!my::DeleteFileX(GetPath(file))) - LOG(LERROR, (file, "from", *this, "wasn't deleted from disk.")); - } + if (OnDisk(file)) + VERIFY(my::DeleteFileX(GetPath(file)), (file, "from", *this, "wasn't deleted from disk.")); } } diff --git a/platform/local_country_file.hpp b/platform/local_country_file.hpp index 1a2afa0180..c73975f772 100644 --- a/platform/local_country_file.hpp +++ b/platform/local_country_file.hpp @@ -25,9 +25,8 @@ public: // their sizes etc. with disk. void SyncWithDisk(); - // Removes specified files from disk if they're known for LocalCountryFile, i.e. - // were found by previous SyncWithDisk() call. - void DeleteFromDisk(TMapOptions files) const; + // Removes known country files from disk. + void DeleteFromDisk(); // Returns path to a file. Return value may be empty until // SyncWithDisk() is called. @@ -48,7 +47,6 @@ public: return (static_cast<unsigned>(m_files) & static_cast<unsigned>(filesMask)) == static_cast<unsigned>(filesMask); } - inline string const & GetDirectory() const { return m_directory; } inline int64_t GetVersion() const { return m_version; } inline CountryFile const & GetCountryFile() const { return m_countryFile; } diff --git a/platform/local_country_file_utils.cpp b/platform/local_country_file_utils.cpp index b5ded8a11c..87e76142d3 100644 --- a/platform/local_country_file_utils.cpp +++ b/platform/local_country_file_utils.cpp @@ -1,16 +1,12 @@ #include "platform/local_country_file_utils.hpp" #include "platform/platform.hpp" - #include "coding/file_name_utils.hpp" #include "coding/file_writer.hpp" - #include "base/string_utils.hpp" #include "base/logging.hpp" - #include "std/algorithm.hpp" #include "std/cctype.hpp" -#include "std/sstream.hpp" namespace platform { @@ -30,11 +26,10 @@ void CleanupMapsDirectory() // Remove partially downloaded maps. { Platform::FilesList files; - // .(downloading|resume|ready)[0-9]?$ - string const regexp = "\\.(downloading|resume|ready)[0-9]?$"; + string const regexp = "\\" DATA_FILE_EXTENSION "\\.(downloading2?$|resume2?$)"; platform.GetFilesByRegExp(mapsDir, regexp, files); for (string const & file : files) - FileWriter::DeleteFileX(my::JoinFoldersToPath(mapsDir, file)); + FileWriter::DeleteFileX(file); } // Find and remove Brazil and Japan maps. @@ -46,7 +41,7 @@ void CleanupMapsDirectory() if (countryFile.GetNameWithoutExt() == "Japan" || countryFile.GetNameWithoutExt() == "Brazil") { localFile.SyncWithDisk(); - localFile.DeleteFromDisk(TMapOptions::EMapWithCarRouting); + localFile.DeleteFromDisk(); } } @@ -109,10 +104,9 @@ void FindAllLocalMaps(vector<LocalCountryFile> & localFiles) { int64_t version; if (ParseVersion(subdir, version)) - FindAllLocalMapsInDirectory(my::JoinFoldersToPath(directory, subdir), version, localFiles); + FindAllLocalMapsInDirectory(my::JoinFoldersToPath(directory, subdir), version, allFiles); } } - #if defined(OMIM_OS_ANDROID) // On Android World and WorldCoasts can be stored in alternative /Android/obb/ path. for (string const & file : {WORLD_FILE_NAME, WORLD_COASTS_FILE_NAME}) @@ -141,6 +135,7 @@ void FindAllLocalMaps(vector<LocalCountryFile> & localFiles) } } #endif // defined(OMIM_OS_ANDROID) + localFiles.insert(localFiles.end(), allFiles.begin(), allFiles.end()); } @@ -148,7 +143,6 @@ bool ParseVersion(string const & s, int64_t & version) { if (s.empty() || s.size() > kMaxTimestampLength) return false; - int64_t v = 0; for (char const c : s) { @@ -168,29 +162,22 @@ shared_ptr<LocalCountryFile> PreparePlaceForCountryFiles(CountryFile const & cou return make_shared<LocalCountryFile>(platform.WritableDir(), countryFile, version); string const directory = my::JoinFoldersToPath(platform.WritableDir(), strings::to_string(version)); - Platform::EError ret = platform.MkDir(directory); - switch (ret) + switch (platform.MkDir(directory)) { case Platform::ERR_OK: return make_shared<LocalCountryFile>(directory, countryFile, version); case Platform::ERR_FILE_ALREADY_EXISTS: { Platform::EFileType type; - if (Platform::GetFileType(directory, type) != Platform::ERR_OK) + if (Platform::GetFileType(directory, type) != Platform::ERR_OK || + type != Platform::FILE_TYPE_DIRECTORY) { - LOG(LERROR, ("Can't determine file type for:", directory)); - return shared_ptr<LocalCountryFile>(); - } - if (type != Platform::FILE_TYPE_DIRECTORY) - { - LOG(LERROR, (directory, "exists, but not a directory:", type)); return shared_ptr<LocalCountryFile>(); } return make_shared<LocalCountryFile>(directory, countryFile, version); } default: - LOG(LERROR, ("Can't prepare place for", countryFile, "(", version, ") :", ret)); return shared_ptr<LocalCountryFile>(); - } + }; } } // namespace platform diff --git a/platform/platform.cpp b/platform/platform.cpp index bfffb65a7c..a5b0f720a5 100644 --- a/platform/platform.cpp +++ b/platform/platform.cpp @@ -1,7 +1,5 @@ #include "platform/platform.hpp" -#include "platform/local_country_file.hpp" - #include "coding/sha2.hpp" #include "coding/base64.hpp" #include "coding/file_name_utils.hpp" @@ -149,9 +147,3 @@ string Platform::GetIndexFileName(string const & mwmName, string const & extensi { return GetPlatform().WritablePathForCountryIndexes(mwmName) + mwmName + extension; } - -ModelReader * Platform::GetCountryReader(platform::LocalCountryFile const & file, - TMapOptions options) const -{ - return GetReader(file.GetPath(options), "f"); -} diff --git a/platform/platform.hpp b/platform/platform.hpp index 7effb78d90..91f86740d7 100644 --- a/platform/platform.hpp +++ b/platform/platform.hpp @@ -1,7 +1,5 @@ #pragma once -#include "platform/country_defines.hpp" - #include "coding/reader.hpp" #include "base/exception.hpp" @@ -14,14 +12,10 @@ #include "defines.hpp" + DECLARE_EXCEPTION(FileAbsentException, RootException); DECLARE_EXCEPTION(NotImplementedException, RootException); -namespace platform -{ -class LocalCountryFile; -} - class Platform { public: @@ -115,9 +109,6 @@ public: /// @return full path to file in the settings directory string SettingsPathForFile(string const & file) const { return SettingsDir() + file; } - ModelReader * GetCountryReader(platform::LocalCountryFile const & file, - TMapOptions options) const; - /// @return reader for file decriptor. /// @throws FileAbsentException /// @param[in] file name or full path which we want to read, don't forget to free memory or wrap it to ReaderPtr diff --git a/platform/platform_android.cpp b/platform/platform_android.cpp index 225547015e..92e6fde61c 100644 --- a/platform/platform_android.cpp +++ b/platform/platform_android.cpp @@ -20,15 +20,8 @@ Platform::Platform() namespace { -enum SourceT -{ - EXTERNAL_RESOURCE, - RESOURCE, - WRITABLE_PATH, - SETTINGS_PATH, - FULL_PATH, - SOURCE_COUNT -}; + +enum SourceT { EXTERNAL_RESOURCE, RESOURCE, WRITABLE_PATH, SETTINGS_PATH, FULL_PATH }; bool IsResource(string const & file, string const & ext) { @@ -47,8 +40,7 @@ bool IsResource(string const & file, string const & ext) return true; } -size_t GetSearchSources(string const & file, string const & searchScope, - SourceT (&arr)[SOURCE_COUNT]) +size_t GetSearchSources(string const & file, string const & searchScope, SourceT (&arr)[4]) { size_t ret = 0; @@ -96,7 +88,7 @@ ModelReader * Platform::GetReader(string const & file, string const & searchScop uint32_t const logPageSize = (ext == DATA_FILE_EXTENSION) ? READER_CHUNK_LOG_SIZE : 10; uint32_t const logPageCount = (ext == DATA_FILE_EXTENSION) ? READER_CHUNK_LOG_COUNT : 4; - SourceT sources[SOURCE_COUNT]; + SourceT sources[4]; size_t n = 0; if (searchScope.empty()) @@ -180,7 +172,6 @@ ModelReader * Platform::GetReader(string const & file, string const & searchScop } } - LOG(LERROR, ("Can't get reader for:", file)); MYTHROW(FileAbsentException, ("File not found", file)); return 0; } @@ -247,9 +238,8 @@ bool Platform::GetFileSizeByName(string const & fileName, uint64_t & size) const size = ReaderPtr<Reader>(GetReader(fileName)).Size(); return true; } - catch (RootException const & ex) + catch (RootException const &) { - LOG(LWARNING, ("Can't get file size for:", fileName)); return false; } } @@ -259,7 +249,7 @@ Platform::EError Platform::MkDir(string const & dirName) const if (mkdir(dirName.c_str(), 0755)) { LOG(LWARNING, ("Can't create directory: ", dirName)); - return ErrnoToError(); + return Platform::ERR_UNKNOWN; } return Platform::ERR_OK; } diff --git a/platform/platform_ios.mm b/platform/platform_ios.mm index cb14de0171..5fd1310059 100644 --- a/platform/platform_ios.mm +++ b/platform/platform_ios.mm @@ -37,7 +37,7 @@ Platform::Platform() Platform::EError Platform::MkDir(string const & dirName) const { if (::mkdir(dirName.c_str(), 0755)) - return ErrnoToError(); + return Platform::ERR_UNKNOWN; return Platform::ERR_OK; } diff --git a/platform/platform_tests/local_country_file_tests.cpp b/platform/platform_tests/local_country_file_tests.cpp index 46981142f6..5594a4e63f 100644 --- a/platform/platform_tests/local_country_file_tests.cpp +++ b/platform/platform_tests/local_country_file_tests.cpp @@ -7,7 +7,6 @@ #include "coding/file_name_utils.hpp" #include "coding/file_writer.hpp" -#include "coding/internal/file_data.hpp" #include "base/scope_guard.hpp" @@ -27,30 +26,24 @@ bool Contains(vector<T> const & v, T const & t) return find(v.begin(), v.end(), t) != v.end(); } -// Scoped test directory in a writable dir. class ScopedTestDir { public: - /// Creates test dir in a writable directory. - /// @param path Path for a testing directory, should be relative to writable-dir. - ScopedTestDir(string const & relativePath) - : m_fullPath(my::JoinFoldersToPath(GetPlatform().WritableDir(), relativePath)), - m_relativePath(relativePath), - m_reset(false) + ScopedTestDir(string const & path) : m_path(path), m_reset(false) { Platform & platform = GetPlatform(); - Platform::EError ret = platform.MkDir(GetFullPath()); + Platform::EError ret = platform.MkDir(m_path); switch (ret) { case Platform::ERR_OK: break; case Platform::ERR_FILE_ALREADY_EXISTS: Platform::EFileType type; - TEST_EQUAL(Platform::ERR_OK, Platform::GetFileType(GetFullPath(), type), ()); + TEST_EQUAL(Platform::ERR_OK, Platform::GetFileType(m_path, type), ()); TEST_EQUAL(Platform::FILE_TYPE_DIRECTORY, type, ()); break; default: - CHECK(false, ("Can't create directory:", GetFullPath(), "error:", ret)); + CHECK(false, ("Can't create directory:", m_path, "error:", ret)); break; } } @@ -60,100 +53,43 @@ public: if (m_reset) return; - string const fullPath = GetFullPath(); - Platform::EError ret = Platform::RmDir(fullPath); + Platform::EError ret = Platform::RmDir(m_path); switch (ret) { case Platform::ERR_OK: break; case Platform::ERR_FILE_DOES_NOT_EXIST: - LOG(LWARNING, (fullPath, "was deleted before destruction of ScopedTestDir.")); + LOG(LWARNING, (m_path, "was deleted before destruction of ScopedTestDir.")); break; case Platform::ERR_DIRECTORY_NOT_EMPTY: - LOG(LWARNING, ("There are files in", fullPath)); + LOG(LWARNING, ("There are files in", m_path)); break; default: - LOG(LWARNING, ("Platform::RmDir() error for", fullPath, ":", ret)); + LOG(LWARNING, ("Platform::RmDir() error:", ret)); break; } } inline void Reset() { m_reset = true; } - inline string const & GetFullPath() const { return m_fullPath; } - - inline string const & GetRelativePath() const { return m_relativePath; } - - bool Exists() const { return GetPlatform().IsFileExistsByFullPath(GetFullPath()); } + inline string const GetPath() const { return m_path; } private: - string const m_fullPath; - string const m_relativePath; + string const m_path; bool m_reset; DISALLOW_COPY_AND_MOVE(ScopedTestDir); }; -class ScopedTestFile +void CreateTestFile(string const & testFile, string const & contents) { -public: - ScopedTestFile(string const & relativePath, string const & contents) - : m_fullPath(my::JoinFoldersToPath(GetPlatform().WritableDir(), relativePath)), m_reset(false) - { - { - FileWriter writer(GetFullPath()); - writer.Write(contents.data(), contents.size()); - } - TEST(Exists(), ("Can't create test file", GetFullPath())); - } - - ScopedTestFile(ScopedTestDir const & dir, CountryFile const & countryFile, TMapOptions file, - string const & contents) - : ScopedTestFile( - my::JoinFoldersToPath(dir.GetRelativePath(), countryFile.GetNameWithExt(file)), - contents) { + FileWriter writer(testFile); + writer.Write(contents.data(), contents.size()); } - - ~ScopedTestFile() - { - if (m_reset) - return; - if (!Exists()) - { - LOG(LWARNING, ("File", GetFullPath(), "was deleted before dtor of ScopedTestFile.")); - return; - } - if (!my::DeleteFileX(GetFullPath())) - LOG(LWARNING, ("Can't remove test file:", GetFullPath())); - } - - inline string const & GetFullPath() const { return m_fullPath; } - - inline void Reset() { m_reset = true; } - - bool Exists() const { return GetPlatform().IsFileExistsByFullPath(GetFullPath()); } - -private: - string const m_fullPath; - bool m_reset; - - DISALLOW_COPY_AND_MOVE(ScopedTestFile); -}; - -string DebugPrint(ScopedTestDir const & dir) -{ - ostringstream os; - os << "ScopedTestDir [" << dir.GetFullPath() << "]"; - return os.str(); + TEST(Platform::IsFileExistsByFullPath(testFile), ("Can't create test file", testFile)); } -string DebugPrint(ScopedTestFile const & file) -{ - ostringstream os; - os << "ScopedTestFile [" << file.GetFullPath() << "]"; - return os.str(); -} } // namespace // Checks that all unsigned numbers less than 10 ^ 18 can be parsed as @@ -224,12 +160,17 @@ UNIT_TEST(LocalCountryFile_DiskFiles) CountryFile countryFile("TestCountry"); countryFile.SetRemoteSizes(1 /* mapSize */, 2 /* routingSize */); + string const testMapFile = + my::JoinFoldersToPath(platform.WritableDir(), countryFile.GetNameWithExt(TMapOptions::EMap)); + string const testRoutingFile = my::JoinFoldersToPath( + platform.WritableDir(), countryFile.GetNameWithExt(TMapOptions::ECarRouting)); + LocalCountryFile localFile(platform.WritableDir(), countryFile, 0 /* version */); TEST(!localFile.OnDisk(TMapOptions::EMap), ()); TEST(!localFile.OnDisk(TMapOptions::ECarRouting), ()); TEST(!localFile.OnDisk(TMapOptions::EMapWithCarRouting), ()); - ScopedTestFile testMapFile(countryFile.GetNameWithExt(TMapOptions::EMap), "map"); + CreateTestFile(testMapFile, "map"); localFile.SyncWithDisk(); TEST(localFile.OnDisk(TMapOptions::EMap), ()); @@ -237,7 +178,7 @@ UNIT_TEST(LocalCountryFile_DiskFiles) TEST(!localFile.OnDisk(TMapOptions::EMapWithCarRouting), ()); TEST_EQUAL(3, localFile.GetSize(TMapOptions::EMap), ()); - ScopedTestFile testRoutingFile(countryFile.GetNameWithExt(TMapOptions::ECarRouting), "routing"); + CreateTestFile(testRoutingFile, "routing"); localFile.SyncWithDisk(); TEST(localFile.OnDisk(TMapOptions::EMap), ()); @@ -247,15 +188,14 @@ UNIT_TEST(LocalCountryFile_DiskFiles) TEST_EQUAL(7, localFile.GetSize(TMapOptions::ECarRouting), ()); TEST_EQUAL(10, localFile.GetSize(TMapOptions::EMapWithCarRouting), ()); - localFile.DeleteFromDisk(TMapOptions::EMapWithCarRouting); - TEST(!testMapFile.Exists(), (testMapFile, "wasn't deleted by LocalCountryFile.")); - testMapFile.Reset(); - - TEST(!testRoutingFile.Exists(), (testRoutingFile, "wasn't deleted by LocalCountryFile.")); - testRoutingFile.Reset(); + localFile.DeleteFromDisk(); + TEST(!platform.IsFileExistsByFullPath(testMapFile), + ("Map file", testMapFile, "wasn't deleted by LocalCountryFile.")); + TEST(!platform.IsFileExistsByFullPath(testRoutingFile), + ("Routing file", testRoutingFile, "wasn't deleted by LocalCountryFile.")); } -UNIT_TEST(LocalCountryFile_CleanupMapFiles) +UNIT_TEST(LocalCountryFile_DirectoryCleanup) { Platform & platform = GetPlatform(); string const mapsDir = platform.WritableDir(); @@ -264,19 +204,19 @@ UNIT_TEST(LocalCountryFile_CleanupMapFiles) CountryFile brazilFile("Brazil"); CountryFile irelandFile("Ireland"); - ScopedTestDir testDir1("1"); - LocalCountryFile japanLocalFile(testDir1.GetFullPath(), japanFile, 1 /* version */); - ScopedTestFile japanMapFile(testDir1, japanFile, TMapOptions::EMap, "Japan"); + ScopedTestDir testDir1(my::JoinFoldersToPath(mapsDir, "1")); + LocalCountryFile japanLocalFile(testDir1.GetPath(), japanFile, 1 /* version */); + CreateTestFile(japanLocalFile.GetPath(TMapOptions::EMap), "Japan"); + + ScopedTestDir testDir2(my::JoinFoldersToPath(mapsDir, "2")); + LocalCountryFile brazilLocalFile(testDir2.GetPath(), brazilFile, 2 /* version */); + CreateTestFile(brazilLocalFile.GetPath(TMapOptions::EMap), "Brazil"); - ScopedTestDir testDir2("2"); - LocalCountryFile brazilLocalFile(testDir2.GetFullPath(), brazilFile, 2 /* version */); - ScopedTestFile brazilMapFile(testDir2, brazilFile, TMapOptions::EMap, "Brazil"); - LocalCountryFile irelandLocalFile(testDir2.GetFullPath(), irelandFile, 2 /* version */); - ScopedTestFile irelandMapFile(testDir2, irelandFile, TMapOptions::EMap, "Ireland"); + ScopedTestDir testDir3(my::JoinFoldersToPath(mapsDir, "3")); - ScopedTestDir testDir3("3"); + LocalCountryFile irelandLocalFile(testDir2.GetPath(), irelandFile, 2 /* version */); + CreateTestFile(irelandLocalFile.GetPath(TMapOptions::EMap), "Ireland"); - // Check that FindAllLocalMaps() vector<LocalCountryFile> localFiles; FindAllLocalMaps(localFiles); TEST(Contains(localFiles, japanLocalFile), (japanLocalFile)); @@ -287,47 +227,20 @@ UNIT_TEST(LocalCountryFile_CleanupMapFiles) japanLocalFile.SyncWithDisk(); TEST_EQUAL(TMapOptions::ENothing, japanLocalFile.GetFiles(), ()); - TEST(!testDir1.Exists(), ("Empty directory", testDir1, "wasn't removed.")); + TEST(!Platform::IsFileExistsByFullPath(testDir1.GetPath()), ("Empty directory wasn't removed.")); testDir1.Reset(); - TEST(!japanMapFile.Exists(), (japanMapFile)); - japanMapFile.Reset(); brazilLocalFile.SyncWithDisk(); TEST_EQUAL(TMapOptions::ENothing, brazilLocalFile.GetFiles(), ()); - TEST(!brazilMapFile.Exists(), (brazilMapFile)); - brazilMapFile.Reset(); irelandLocalFile.SyncWithDisk(); TEST_EQUAL(TMapOptions::EMap, irelandLocalFile.GetFiles(), ()); - irelandLocalFile.DeleteFromDisk(TMapOptions::EMap); - TEST(!irelandMapFile.Exists(), (irelandMapFile)); - irelandMapFile.Reset(); + irelandLocalFile.DeleteFromDisk(); - TEST(!testDir3.Exists(), ("Empty directory", testDir3, "wasn't removed.")); + TEST(!Platform::IsFileExistsByFullPath(testDir3.GetPath()), ("Empty directory wasn't removed.")); testDir3.Reset(); } -UNIT_TEST(LocalCountryFile_CleanupPartiallyDownloadedFiles) -{ - ScopedTestFile toBeDeleted[] = {{"Ireland.mwm.ready", "Ireland"}, - {"Netherlands.mwm.routing.downloading2", "Netherlands"}, - {"Germany.mwm.ready3", "Germany"}, - {"UK_England.mwm.resume4", "UK"}}; - ScopedTestFile toBeKept[] = { - {"Italy.mwm", "Italy"}, {"Spain.mwm", "Spain map"}, {"Spain.mwm.routing", "Spain routing"}}; - - CleanupMapsDirectory(); - - for (ScopedTestFile & file : toBeDeleted) - { - TEST(!file.Exists(), (file)); - file.Reset(); - } - - for (ScopedTestFile & file : toBeKept) - TEST(file.Exists(), (file)); -} - // Creates test-dir and following files: // * test-dir/Ireland.mwm // * test-dir/Netherlands.mwm @@ -340,24 +253,37 @@ UNIT_TEST(LocalCountryFile_DirectoryLookup) CountryFile const irelandFile("Ireland"); CountryFile const netherlandsFile("Netherlands"); - ScopedTestDir testDir("test-dir"); + Platform & platform = GetPlatform(); + + ScopedTestDir testDir(my::JoinFoldersToPath(platform.WritableDir(), "test-dir")); + + string const testIrelandMapFile = + my::JoinFoldersToPath(testDir.GetPath(), irelandFile.GetNameWithExt(TMapOptions::EMap)); + CreateTestFile(testIrelandMapFile, "Ireland-map"); + MY_SCOPE_GUARD(removeTestIrelandMapFile, bind(&FileWriter::DeleteFileX, testIrelandMapFile)); - ScopedTestFile testIrelandMapFile(testDir, irelandFile, TMapOptions::EMap, "Ireland-map"); - ScopedTestFile testNetherlandsMapFile(testDir, netherlandsFile, TMapOptions::EMap, - "Netherlands-map"); - ScopedTestFile testNetherlandsRoutingFile(testDir, netherlandsFile, TMapOptions::ECarRouting, - "Netherlands-routing"); + string const testNetherlandsMapFile = + my::JoinFoldersToPath(testDir.GetPath(), netherlandsFile.GetNameWithExt(TMapOptions::EMap)); + CreateTestFile(testNetherlandsMapFile, "Netherlands-map"); + MY_SCOPE_GUARD(removeTestNetherlandsMapFile, + bind(&FileWriter::DeleteFileX, testNetherlandsMapFile)); + + string const testNetherlandsRoutingFile = my::JoinFoldersToPath( + testDir.GetPath(), netherlandsFile.GetNameWithExt(TMapOptions::ECarRouting)); + CreateTestFile(testNetherlandsRoutingFile, "Netherlands-routing"); + MY_SCOPE_GUARD(removeTestNetherlandsRoutingFile, + bind(&FileWriter::DeleteFileX, testNetherlandsRoutingFile)); vector<LocalCountryFile> localFiles; - FindAllLocalMapsInDirectory(testDir.GetFullPath(), 150309, localFiles); + FindAllLocalMapsInDirectory(testDir.GetPath(), 150309, localFiles); sort(localFiles.begin(), localFiles.end()); for (LocalCountryFile & localFile : localFiles) localFile.SyncWithDisk(); - LocalCountryFile expectedIrelandFile(testDir.GetFullPath(), irelandFile, 150309); + LocalCountryFile expectedIrelandFile(testDir.GetPath(), irelandFile, 150309); expectedIrelandFile.m_files = TMapOptions::EMap; - LocalCountryFile expectedNetherlandsFile(testDir.GetFullPath(), netherlandsFile, 150309); + LocalCountryFile expectedNetherlandsFile(testDir.GetPath(), netherlandsFile, 150309); expectedNetherlandsFile.m_files = TMapOptions::EMapWithCarRouting; vector<LocalCountryFile> expectedLocalFiles = {expectedIrelandFile, expectedNetherlandsFile}; @@ -375,8 +301,12 @@ UNIT_TEST(LocalCountryFile_AllLocalFilesLookup) Platform & platform = GetPlatform(); - ScopedTestDir testDir("010101"); - ScopedTestFile testItalyMapFile(testDir, italyFile, TMapOptions::EMap, "Italy-map"); + ScopedTestDir testDir(my::JoinFoldersToPath(platform.WritableDir(), "010101")); + + string const testItalyMapFile = + my::JoinFoldersToPath(testDir.GetPath(), italyFile.GetNameWithExt(TMapOptions::EMap)); + CreateTestFile(testItalyMapFile, "Italy-map"); + MY_SCOPE_GUARD(remoteTestItalyMapFile, bind(&FileWriter::DeleteFileX, testItalyMapFile)); vector<LocalCountryFile> localFiles; FindAllLocalMaps(localFiles); @@ -390,7 +320,7 @@ UNIT_TEST(LocalCountryFile_AllLocalFilesLookup) CountryFile(WORLD_COASTS_FILE_NAME), 0 /* version */); TEST_EQUAL(1, localFilesSet.count(expectedWorldCoastsFile), ()); - LocalCountryFile expectedItalyFile(testDir.GetFullPath(), italyFile, 10101); + LocalCountryFile expectedItalyFile(testDir.GetPath(), italyFile, 10101); TEST_EQUAL(1, localFilesSet.count(expectedItalyFile), ()); } @@ -405,17 +335,17 @@ UNIT_TEST(LocalCountryFile_PreparePlaceForCountryFiles) TEST(italyLocalFile.get(), ()); TEST_EQUAL(expectedItalyFile, *italyLocalFile, ()); - ScopedTestDir directoryForV1("1"); + ScopedTestDir directoryForV1(my::JoinFoldersToPath(platform.WritableDir(), "1")); CountryFile germanyFile("Germany"); - LocalCountryFile expectedGermanyFile(directoryForV1.GetFullPath(), germanyFile, 1 /* version */); + LocalCountryFile expectedGermanyFile(directoryForV1.GetPath(), germanyFile, 1 /* version */); shared_ptr<LocalCountryFile> germanyLocalFile = PreparePlaceForCountryFiles(germanyFile, 1 /* version */); TEST(germanyLocalFile.get(), ()); TEST_EQUAL(expectedGermanyFile, *germanyLocalFile, ()); CountryFile franceFile("France"); - LocalCountryFile expectedFranceFile(directoryForV1.GetFullPath(), franceFile, 1 /* version */); + LocalCountryFile expectedFranceFile(directoryForV1.GetPath(), franceFile, 1 /* version */); shared_ptr<LocalCountryFile> franceLocalFile = PreparePlaceForCountryFiles(franceFile, 1 /* version */); TEST(franceLocalFile.get(), ()); diff --git a/routing/osrm_router.cpp b/routing/osrm_router.cpp index e52a2bc6c8..1fb3840e50 100644 --- a/routing/osrm_router.cpp +++ b/routing/osrm_router.cpp @@ -4,7 +4,6 @@ #include "turns_generator.hpp" #include "vehicle_model.hpp" -#include "platform/country_file.hpp" #include "platform/platform.hpp" #include "geometry/angles.hpp" @@ -350,12 +349,9 @@ public: }; } // namespace -OsrmRouter::OsrmRouter(Index const * index, TCountryFileFn const & countryFileFn, - TCountryLocalFileFn const & countryLocalFileFn, +OsrmRouter::OsrmRouter(Index const * index, TCountryFileFn const & fn, TRoutingVisualizerFn routingVisualization) - : m_pIndex(index), - m_indexManager(countryFileFn, countryLocalFileFn, index), - m_routingVisualization(routingVisualization) + : m_pIndex(index), m_indexManager(fn, index), m_routingVisualization(routingVisualization) { } diff --git a/routing/osrm_router.hpp b/routing/osrm_router.hpp index 813fffd1cd..3eac5e9483 100644 --- a/routing/osrm_router.hpp +++ b/routing/osrm_router.hpp @@ -28,17 +28,18 @@ namespace routing struct RoutePathCross; using TCheckedPath = vector<RoutePathCross>; +typedef OsrmDataFacade<QueryEdge::EdgeData> TDataFacade; + /// All edges available for start route while routing typedef vector<FeatureGraphNode> TFeatureGraphNodeVec; + class OsrmRouter : public IRouter { public: typedef vector<double> GeomTurnCandidateT; - OsrmRouter(Index const * index, TCountryFileFn const & countryFileFn, - TCountryLocalFileFn const & countryLocalFileFn, - TRoutingVisualizerFn routingVisualization = nullptr); + OsrmRouter(Index const * index, TCountryFileFn const & fn, TRoutingVisualizerFn routingVisualization = nullptr); virtual string GetName() const; diff --git a/routing/road_graph_router.cpp b/routing/road_graph_router.cpp index 3f1a1b67cc..7224e73d34 100644 --- a/routing/road_graph_router.cpp +++ b/routing/road_graph_router.cpp @@ -92,8 +92,7 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin if (m_countryFileFn(startPoint) != mwmName) return PointsInDifferentMWM; - platform::CountryFile countryFile(mwmName); - MwmSet::MwmLock const mwmLock = const_cast<Index &>(m_index).GetMwmLockByCountryFile(countryFile); + MwmSet::MwmLock const mwmLock = const_cast<Index&>(m_index).GetMwmLockByFileName(mwmName); if (!mwmLock.IsLocked()) return RouteFileNotExist; diff --git a/routing/routing_mapping.cpp b/routing/routing_mapping.cpp index a7c6f3bf97..1d2001c578 100644 --- a/routing/routing_mapping.cpp +++ b/routing/routing_mapping.cpp @@ -10,49 +10,34 @@ #include "indexer/mwm_version.hpp" -#include "platform/country_file.hpp" -#include "platform/local_country_file.hpp" #include "platform/platform.hpp" -using platform::CountryFile; -using platform::LocalCountryFile; - namespace routing { -RoutingMapping::RoutingMapping(CountryFile const & countryFile) +RoutingMapping::RoutingMapping(string const & fName, Index const * pIndex) : m_mapCounter(0), m_facadeCounter(0), m_crossContextLoaded(0), - m_countryFileName(countryFile.GetNameWithoutExt()), - m_isValid(false), - m_error(IRouter::ResultCode::RouteFileNotExist) -{ -} - -RoutingMapping::RoutingMapping(LocalCountryFile const & localFile, Index const * pIndex) - : m_mapCounter(0), - m_facadeCounter(0), - m_crossContextLoaded(0), - m_countryFileName(localFile.GetCountryFile().GetNameWithoutExt()), + m_baseName(fName), m_isValid(true), m_error(IRouter::ResultCode::NoError) { Platform & pl = GetPlatform(); - if (!HasOptions(localFile.GetFiles(), TMapOptions::EMapWithCarRouting)) + string const mwmName = m_baseName + DATA_FILE_EXTENSION; + string const fPath = pl.WritablePathForFile(mwmName + ROUTING_FILE_EXTENSION); + if (!pl.IsFileExistsByFullPath(fPath)) { m_isValid = false; m_error = IRouter::ResultCode::RouteFileNotExist; return; } - string const routingFilePath = localFile.GetPath(TMapOptions::ECarRouting); // Open new container and check that mwm and routing have equal timestamp. - LOG(LDEBUG, ("Load routing index for file:", routingFilePath)); - m_container.Open(routingFilePath); + LOG(LDEBUG, ("Load routing index for file:", fPath)); + m_container.Open(fPath); { FileReader r1 = m_container.GetReader(VERSION_FILE_TAG); ReaderSrc src1(r1); - ModelReaderPtr r2 = FilesContainerR(pl.GetCountryReader(localFile, TMapOptions::EMap)) - .GetReader(VERSION_FILE_TAG); + ModelReaderPtr r2 = FilesContainerR(pl.GetReader(mwmName)).GetReader(VERSION_FILE_TAG); ReaderSrc src2(r2.GetPtr()); version::MwmVersion version1; @@ -70,7 +55,7 @@ RoutingMapping::RoutingMapping(LocalCountryFile const & localFile, Index const * } } - m_mwmId = pIndex->GetMwmIdByCountryFile(localFile.GetCountryFile()); + m_mwmId = pIndex->GetMwmIdByFileName(mwmName); } RoutingMapping::~RoutingMapping() @@ -128,33 +113,22 @@ void RoutingMapping::FreeCrossContext() m_crossContext = CrossRoutingContextReader(); } -// static -shared_ptr<RoutingMapping> RoutingMapping::MakeInvalid(platform::CountryFile const & countryFile) -{ - return shared_ptr<RoutingMapping>(new RoutingMapping(countryFile)); -} - TRoutingMappingPtr RoutingIndexManager::GetMappingByPoint(m2::PointD const & point) { - return GetMappingByName(m_countryFileFn(point)); + return GetMappingByName(m_countryFn(point)); } TRoutingMappingPtr RoutingIndexManager::GetMappingByName(string const & mapName) { - shared_ptr<platform::LocalCountryFile> localFile = m_countryLocalFileFn(mapName); - // Return invalid mapping when file does not exist. - if (!localFile) - return RoutingMapping::MakeInvalid(platform::CountryFile(mapName)); - // Check if we have already loaded this file. auto mapIter = m_mapping.find(mapName); if (mapIter != m_mapping.end()) return mapIter->second; // Or load and check file. - TRoutingMappingPtr newMapping = make_shared<RoutingMapping>(*localFile, m_index); - m_mapping.insert(make_pair(mapName, newMapping)); - return newMapping; + TRoutingMappingPtr new_mapping = make_shared<RoutingMapping>(mapName, m_index); + m_mapping.insert(make_pair(mapName, new_mapping)); + return new_mapping; } } // namespace routing diff --git a/routing/routing_mapping.h b/routing/routing_mapping.h index 41d0b0da50..e791599f30 100644 --- a/routing/routing_mapping.h +++ b/routing/routing_mapping.h @@ -11,17 +11,10 @@ #include "std/algorithm.hpp" #include "std/unordered_map.hpp" -namespace platform -{ -class CountryFile; -class LocalCountryFile; -} - namespace routing { using TDataFacade = OsrmDataFacade<QueryEdge::EdgeData>; using TCountryFileFn = function<string(m2::PointD const &)>; -using TCountryLocalFileFn = function<shared_ptr<platform::LocalCountryFile>(string const &)>; /// Datamapping and facade for single MWM and MWM.routing file struct RoutingMapping @@ -31,7 +24,7 @@ struct RoutingMapping CrossRoutingContextReader m_crossContext; ///@param fName: mwm file path - RoutingMapping(platform::LocalCountryFile const & localFile, Index const * pIndex); + RoutingMapping(string const & fName, Index const * pIndex); ~RoutingMapping(); @@ -51,21 +44,15 @@ struct RoutingMapping IRouter::ResultCode GetError() const {return m_error;} - string const & GetName() const { return m_countryFileName; } + string const & GetName() const { return m_baseName; } Index::MwmId const & GetMwmId() const { return m_mwmId; } - // static - static shared_ptr<RoutingMapping> MakeInvalid(platform::CountryFile const & countryFile); - private: - // Ctor for invalid mappings. - RoutingMapping(platform::CountryFile const & countryFile); - size_t m_mapCounter; size_t m_facadeCounter; bool m_crossContextLoaded; - string m_countryFileName; + string m_baseName; FilesMappingContainer m_container; Index::MwmId m_mwmId; bool m_isValid; @@ -99,9 +86,8 @@ public: class RoutingIndexManager { public: - RoutingIndexManager(TCountryFileFn const & countryFileFn, - TCountryLocalFileFn const & countryLocalFileFn, Index const * index) - : m_countryFileFn(countryFileFn), m_countryLocalFileFn(countryLocalFileFn), m_index(index) + RoutingIndexManager(TCountryFileFn const & fn, Index const * index) + : m_countryFn(fn), m_index(index) { ASSERT(index, ()); } @@ -119,10 +105,9 @@ public: void Clear() { m_mapping.clear(); } private: - TCountryFileFn m_countryFileFn; - TCountryLocalFileFn m_countryLocalFileFn; - unordered_map<string, TRoutingMappingPtr> m_mapping; + TCountryFileFn m_countryFn; Index const * m_index; + unordered_map<string, TRoutingMappingPtr> m_mapping; }; } // namespace routing diff --git a/search/search_query.cpp b/search/search_query.cpp index 12741b473b..0a5eab18d3 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -600,7 +600,7 @@ namespace impl if (m_pFV->IsWorld()) country.clear(); else - country = m_pFV->GetCountryFileName(); + country = m_pFV->GetFileName(); } public: @@ -1659,14 +1659,11 @@ void Query::SearchAddress(Results & res) { MwmSet::MwmId id(info); Index::MwmLock const mwmLock(const_cast<Index &>(*m_pIndex), id); + string fileName; if (mwmLock.IsLocked()) - { - platform::CountryFile const & countryFile = - mwmLock.GetValue<MwmValue>()->GetCountryFile(); - string const countryFileName = countryFile.GetNameWithoutExt(); - if (m_pInfoGetter->IsBelongToRegion(countryFileName, region.m_ids)) - SearchInMWM(mwmLock, params); - } + fileName = mwmLock.GetValue<MwmValue>()->GetFileName(); + if (m_pInfoGetter->IsBelongToRegion(fileName, region.m_ids)) + SearchInMWM(mwmLock, params); } } } @@ -2111,8 +2108,9 @@ void Query::SearchInMWM(Index::MwmLock const & mwmLock, Params const & params, TrieRootPrefix(*pLangRoot, edge), filter, categoriesHolder, emitter); - LOG(LDEBUG, ("Country", pMwm->GetCountryFile().GetNameWithoutExt(), "Lang", - StringUtf8Multilang::GetLangByCode(lang), "Matched", emitter.GetCount())); + LOG(LDEBUG, ("Country", pMwm->GetFileName(), + "Lang", StringUtf8Multilang::GetLangByCode(lang), + "Matched", emitter.GetCount())); emitter.Reset(); } @@ -2195,11 +2193,8 @@ void Query::SearchAdditional(Results & res, size_t resCount) for (shared_ptr<MwmInfo> const & info : mwmsInfo) { Index::MwmLock const mwmLock(const_cast<Index &>(*m_pIndex), MwmSet::MwmId(info)); - if (mwmLock.IsLocked() && - mwmLock.GetValue<MwmValue>()->GetCountryFile().GetNameWithoutExt() == fileName) - { + if (mwmLock.IsLocked() && mwmLock.GetValue<MwmValue>()->GetFileName() == fileName) SearchInMWM(mwmLock, params); - } } FlushResults(res, true, resCount); diff --git a/search/search_tests/house_detector_tests.cpp b/search/search_tests/house_detector_tests.cpp index eae291fb9a..1f03cb824d 100644 --- a/search/search_tests/house_detector_tests.cpp +++ b/search/search_tests/house_detector_tests.cpp @@ -17,7 +17,6 @@ #include "std/iostream.hpp" #include "std/fstream.hpp" -using platform::LocalCountryFile; class StreetIDsByName { @@ -184,8 +183,7 @@ UNIT_TEST(HS_StreetsMerge) classificator::Load(); Index index; - pair<MwmSet::MwmLock, bool> const p = - index.Register(LocalCountryFile::MakeForTesting("minsk-pass")); + pair<MwmSet::MwmLock, bool> const p = index.Register("minsk-pass.mwm"); TEST(p.first.IsLocked(), ()); TEST(p.second, ()); @@ -274,8 +272,7 @@ UNIT_TEST(HS_FindHouseSmoke) classificator::Load(); Index index; - pair<MwmSet::MwmLock, bool> const p = - index.Register(LocalCountryFile::MakeForTesting("minsk-pass")); + pair<MwmSet::MwmLock, bool> const p = index.Register("minsk-pass.mwm"); TEST(p.first.IsLocked(), ()); TEST(p.second, ()); @@ -348,7 +345,10 @@ struct Address string m_house; double m_lat, m_lon; - bool operator<(Address const & rhs) const { return (m_streetKey < rhs.m_streetKey); } + bool operator<(Address const & rhs) const + { + return (m_streetKey < rhs.m_streetKey); + } }; void swap(Address & a1, Address & a2) @@ -375,7 +375,7 @@ UNIT_TEST(HS_MWMSearch) } Index index; - pair<MwmSet::MwmLock, bool> const p = index.Register(LocalCountryFile::MakeForTesting(country)); + pair<MwmSet::MwmLock, bool> const p = index.Register(country + ".mwm"); if (!p.second) { LOG(LWARNING, ("MWM file not found")); diff --git a/search/search_tests/locality_finder_test.cpp b/search/search_tests/locality_finder_test.cpp index 62efda0f5e..30182f7267 100644 --- a/search/search_tests/locality_finder_test.cpp +++ b/search/search_tests/locality_finder_test.cpp @@ -5,10 +5,6 @@ #include "search/locality_finder.hpp" -#include "platform/country_file.hpp" -#include "platform/local_country_file.hpp" -#include "platform/platform.hpp" - namespace { @@ -38,8 +34,7 @@ void doTests2(search::LocalityFinder & finder, vector<m2::PointD> const & input, UNIT_TEST(LocalityFinder) { Index index; - pair<MwmSet::MwmLock, bool> const p = - index.Register(platform::LocalCountryFile::MakeForTesting("World")); + pair<MwmSet::MwmLock, bool> const p = index.Register("World.mwm"); TEST(p.second, ()); MwmSet::MwmLock const & lock = p.first; TEST(lock.IsLocked(), ()); diff --git a/std/algorithm.hpp b/std/algorithm.hpp index 913e1c0482..426296336b 100644 --- a/std/algorithm.hpp +++ b/std/algorithm.hpp @@ -6,7 +6,6 @@ #include <algorithm> -using std::all_of; using std::binary_search; using std::equal; using std::find; diff --git a/storage/country.cpp b/storage/country.cpp index d2be152219..3e39eb674a 100644 --- a/storage/country.cpp +++ b/storage/country.cpp @@ -6,19 +6,96 @@ #include "3party/jansson/myjansson.hpp" -using platform::CountryFile; namespace storage { -uint64_t Country::Size(TMapOptions opt) const + +string CountryFile::GetFileWithExt(TMapOptions opt) const +{ + switch (opt) + { + case TMapOptions::EMap: return m_fileName + DATA_FILE_EXTENSION; + case TMapOptions::ECarRouting: return m_fileName + DATA_FILE_EXTENSION + ROUTING_FILE_EXTENSION; + + case TMapOptions::EMapWithCarRouting: + default: + ASSERT(false, ()); + } + return string(); +} + +uint32_t CountryFile::GetFileSize(TMapOptions opt) const { uint64_t size = 0; - for (CountryFile const & file : m_files) - size += file.GetRemoteSize(opt); - return size; + if (GetPlatform().GetFileSizeByName(GetFileWithExt(opt), size)) + { + uint32_t const ret = static_cast<uint32_t>(size); + ASSERT_EQUAL ( ret, size, () ); + return ret; + } + else + return 0; +} + +uint32_t CountryFile::GetRemoteSize(TMapOptions opt) const +{ + switch (opt) + { + case TMapOptions::ENothing: + return 0; + case TMapOptions::EMap: + return m_mapSize; + case TMapOptions::ECarRouting: + return m_routingSize; + case TMapOptions::EMapWithCarRouting: + return m_mapSize + m_routingSize; + } +} + +/* +class CountryBoundsCalculator +{ + m2::RectD & m_bounds; + Platform & m_platform; + +public: + CountryBoundsCalculator(m2::RectD & bounds) + : m_bounds(bounds), m_platform(GetPlatform()) + { + } + + void operator()(CountryFile const & file) + { + feature::DataHeader h; + LoadMapHeader(m_platform.GetReader(file.GetFileWithExt()), h); + m_bounds.Add(h.GetBounds()); + } +}; + +m2::RectD Country::Bounds() const +{ + m2::RectD bounds; + std::for_each(m_files.begin(), m_files.end(), CountryBoundsCalculator(bounds)); + return bounds; +} +*/ + +LocalAndRemoteSizeT Country::Size(TMapOptions opt) const +{ + uint64_t localSize = 0, remoteSize = 0; + for (CountryFile const & f : m_files) + { + localSize += f.GetFileSize(opt); + remoteSize += f.GetRemoteSize(opt); + } + return LocalAndRemoteSizeT(localSize, remoteSize); +} + +void Country::AddFile(CountryFile const & file) +{ + m_files.push_back(file); } -void Country::AddFile(CountryFile const & file) { m_files.push_back(file); } //////////////////////////////////////////////////////////////////////// @@ -41,9 +118,10 @@ void LoadGroupImpl(int depth, json_t * group, ToDo & toDo) char const * flag = json_string_value(json_object_get(j, "c")); toDo(name, file, flag ? flag : "", - // We expect what mwm and routing files should be less 2Gb + // We expect what mwm and routing files should be less 2Gb static_cast<uint32_t>(json_integer_value(json_object_get(j, "s"))), - static_cast<uint32_t>(json_integer_value(json_object_get(j, "rs"))), depth); + static_cast<uint32_t>(json_integer_value(json_object_get(j, "rs"))), + depth); json_t * children = json_object_get(j, "g"); if (children) @@ -52,133 +130,120 @@ void LoadGroupImpl(int depth, json_t * group, ToDo & toDo) } template <class ToDo> -bool LoadCountriesImpl(string const & jsonBuffer, ToDo & toDo) +int64_t LoadCountriesImpl(string const & jsonBuffer, ToDo & toDo) { + int64_t version = -1; + try { my::Json root(jsonBuffer.c_str()); + version = json_integer_value(json_object_get(root.get(), "v")); json_t * children = json_object_get(root.get(), "g"); if (!children) MYTHROW(my::Json::Exception, ("Root country doesn't have any groups")); LoadGroupImpl(0, children, toDo); - return true; } - catch (my::Json::Exception const & e) + catch (my::Json::Exception const & ex) { - LOG(LERROR, (e.Msg())); - return false; + LOG(LERROR, (ex.Msg())); + return -1; } + + return version; } namespace { -class DoStoreCountries -{ - CountriesContainerT & m_cont; - -public: - DoStoreCountries(CountriesContainerT & cont) : m_cont(cont) {} - - void operator()(string const & name, string const & file, string const & flag, uint32_t mapSize, - uint32_t routingSize, int depth) + class DoStoreCountries { - Country country(name, flag); - if (mapSize) + CountriesContainerT & m_cont; + public: + DoStoreCountries(CountriesContainerT & cont) : m_cont(cont) {} + + void operator() (string const & name, string const & file, string const & flag, + uint32_t mapSize, uint32_t routingSize, int depth) { - CountryFile countryFile(file); - countryFile.SetRemoteSizes(mapSize, routingSize); - country.AddFile(countryFile); + Country country(name, flag); + if (mapSize) + country.AddFile(CountryFile(file, mapSize, routingSize)); + m_cont.AddAtDepth(depth, country); } - m_cont.AddAtDepth(depth, country); - } -}; + }; -class DoStoreFile2Info -{ - map<string, CountryInfo> & m_file2info; - string m_lastFlag; - -public: - DoStoreFile2Info(map<string, CountryInfo> & file2info) : m_file2info(file2info) {} - - void operator()(string name, string file, string const & flag, uint32_t mapSize, uint32_t, int) + class DoStoreFile2Info { - if (!flag.empty()) - m_lastFlag = flag; + map<string, CountryInfo> & m_file2info; + string m_lastFlag; - if (mapSize) + public: + DoStoreFile2Info(map<string, CountryInfo> & file2info) : m_file2info(file2info) {} + + void operator() (string name, string file, string const & flag, + uint32_t mapSize, uint32_t, int) { - CountryInfo info; + if (!flag.empty()) + m_lastFlag = flag; - // if 'file' is empty - it's equal to 'name' - if (!file.empty()) + if (mapSize) { - // make compound name: country_region - size_t const i = file.find_first_of('_'); - if (i != string::npos) - name = file.substr(0, i) + '_' + name; - - // fill 'name' only when it differs with 'file' - if (name != file) - info.m_name.swap(name); - } - else - file.swap(name); + CountryInfo info; - // Do not use 'name' here! It was swapped! + // if 'file' is empty - it's equal to 'name' + if (!file.empty()) + { + // make compound name: country_region + size_t const i = file.find_first_of('_'); + if (i != string::npos) + name = file.substr(0, i) + '_' + name; - ASSERT(!m_lastFlag.empty(), ()); - info.m_flag = m_lastFlag; + // fill 'name' only when it differs with 'file' + if (name != file) + info.m_name.swap(name); + } + else + file.swap(name); - m_file2info[file] = info; - } - } -}; + // Do not use 'name' here! It was swapped! -class DoStoreCode2File -{ - multimap<string, string> & m_code2file; + ASSERT ( !m_lastFlag.empty(), () ); + info.m_flag = m_lastFlag; -public: - DoStoreCode2File(multimap<string, string> & code2file) : m_code2file(code2file) {} + m_file2info[file] = info; + } + } + }; - void operator()(string const &, string const & file, string const & flag, uint32_t, uint32_t, int) + class DoStoreCode2File { - m_code2file.insert(make_pair(flag, file)); - } -}; + multimap<string, string> & m_code2file; + public: + DoStoreCode2File(multimap<string, string> & code2file) : m_code2file(code2file) {} + + void operator() (string const &, string const & file, string const & flag, + uint32_t, uint32_t, int) + { + m_code2file.insert(make_pair(flag, file)); + } + }; } int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries) { countries.Clear(); - - int64_t version = -1; - try - { - my::Json root(jsonBuffer.c_str()); - version = json_integer_value(json_object_get(root.get(), "v")); - DoStoreCountries doStore(countries); - if (!LoadCountriesImpl(jsonBuffer, doStore)) - return -1; - } - catch (my::Json::Exception const & e) - { - LOG(LERROR, (e.Msg())); - } - return version; + DoStoreCountries doStore(countries); + return LoadCountriesImpl(jsonBuffer, doStore); } void LoadCountryFile2CountryInfo(string const & jsonBuffer, map<string, CountryInfo> & id2info) { - ASSERT(id2info.empty(), ()); + ASSERT ( id2info.empty(), () ); DoStoreFile2Info doStore(id2info); LoadCountriesImpl(jsonBuffer, doStore); } void LoadCountryCode2File(string const & jsonBuffer, multimap<string, string> & code2file) { - ASSERT(code2file.empty(), ()); + ASSERT ( code2file.empty(), () ); DoStoreCode2File doStore(code2file); LoadCountriesImpl(jsonBuffer, doStore); } @@ -208,12 +273,11 @@ void SaveImpl(T const & v, json_t * jParent) if (countriesCount > 0) { CountryFile const & file = v[i].Value().GetFile(); - string const & strFile = file.GetNameWithoutExt(); + string const & strFile = file.GetFileWithoutExt(); if (strFile != strName) json_object_set_new(jCountry.get(), "f", json_string(strFile.c_str())); json_object_set_new(jCountry.get(), "s", json_integer(file.GetRemoteSize(TMapOptions::EMap))); - json_object_set_new(jCountry.get(), "rs", - json_integer(file.GetRemoteSize(TMapOptions::ECarRouting))); + json_object_set_new(jCountry.get(), "rs", json_integer(file.GetRemoteSize(TMapOptions::ECarRouting))); } if (v[i].SiblingsCount()) @@ -240,4 +304,4 @@ bool SaveCountries(int64_t version, CountriesContainerT const & countries, strin return true; } -} // namespace storage +} // namespace storage diff --git a/storage/country.hpp b/storage/country.hpp index a51997be9d..0140722634 100644 --- a/storage/country.hpp +++ b/storage/country.hpp @@ -1,10 +1,8 @@ #pragma once -#include "storage/country_decl.hpp" -#include "storage/simple_tree.hpp" #include "storage/storage_defines.hpp" - -#include "platform/local_country_file.hpp" +#include "storage/simple_tree.hpp" +#include "storage/country_decl.hpp" #include "platform/country_defines.hpp" @@ -17,56 +15,91 @@ #include "std/string.hpp" #include "std/vector.hpp" -namespace update -{ -class SizeUpdater; -} + +namespace update { class SizeUpdater; } namespace storage { -/// Serves as a proxy between GUI and downloaded files -class Country -{ - friend class update::SizeUpdater; - /// Name in the country node tree - string m_name; - /// Flag to display - string m_flag; - /// stores squares with world pieces which are part of the country - buffer_vector<platform::CountryFile, 1> m_files; - -public: - Country() {} - Country(string const & name, string const & flag = "") : m_name(name), m_flag(flag) {} - - bool operator<(Country const & other) const { return Name() < other.Name(); } - - void AddFile(platform::CountryFile const & file); - - size_t GetFilesCount() const { return m_files.size(); } - - /// This function valid for current logic - one file for one country (region). - /// If the logic will be changed, replace GetFile with ForEachFile. - platform::CountryFile const & GetFile() const + /// Information about each file for a country + class CountryFile { - ASSERT_EQUAL(m_files.size(), 1, (m_name)); - return m_files.front(); - } - - string const & Name() const { return m_name; } - string const & Flag() const { return m_flag; } + string m_fileName; /// Same as id of country\region. + uint32_t m_mapSize, m_routingSize; - uint64_t Size(TMapOptions opt) const; -}; + public: + CountryFile() : m_mapSize(0), m_routingSize(0) {} + CountryFile(string const & fName, uint32_t mapSize, uint32_t routingSize) + : m_fileName(fName), m_mapSize(mapSize), m_routingSize(routingSize) + { + } -typedef SimpleTree<Country> CountriesContainerT; + void AssignSizes(uint32_t mapSize, uint32_t routingSize) + { + m_mapSize = mapSize; + m_routingSize = routingSize; + } -/// @return version of country file or -1 if error was encountered -int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries); + string GetFileWithExt(TMapOptions opt) const; + string const & GetFileWithoutExt() const { return m_fileName; } -void LoadCountryFile2CountryInfo(string const & jsonBuffer, map<string, CountryInfo> & id2info); + uint32_t GetFileSize(TMapOptions opt) const; + uint32_t GetRemoteSize(TMapOptions opt) const; + }; -void LoadCountryCode2File(string const & jsonBuffer, multimap<string, string> & code2file); + typedef buffer_vector<CountryFile, 1> FilesContainerT; -bool SaveCountries(int64_t version, CountriesContainerT const & countries, string & jsonBuffer); -} // namespace storage + /// Serves as a proxy between GUI and downloaded files + class Country + { + friend class update::SizeUpdater; + /// Name in the country node tree + string m_name; + /// Flag to display + string m_flag; + /// stores squares with world pieces which are part of the country + FilesContainerT m_files; + + public: + Country() {} + Country(string const & name, string const & flag = "") + : m_name(name), m_flag(flag) {} + + bool operator<(Country const & other) const { return Name() < other.Name(); } + + void AddFile(CountryFile const & file); + + size_t GetFilesCount() const { return m_files.size(); } + + /* + template <class ToDo> void ForEachFile(ToDo toDo) const + { + for (FilesContainerT::const_iterator i = m_files.begin(); i != m_files.end(); ++i) + toDo(i->GetFileWithExt()); + } + */ + + /// This function valid for current logic - one file for one country (region). + /// If the logic will be changed, replace GetFile with ForEachFile. + CountryFile const & GetFile() const + { + ASSERT_EQUAL ( m_files.size(), 1, (m_name) ); + return m_files.front(); + } + + string const & Name() const { return m_name; } + string const & Flag() const { return m_flag; } + + /// @return bounds for downloaded parts of the country or empty rect + //m2::RectD Bounds() const; + LocalAndRemoteSizeT Size(TMapOptions opt) const; + }; + + typedef SimpleTree<Country> CountriesContainerT; + + /// @return version of country file or -1 if error was encountered + int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries); + void LoadCountryFile2CountryInfo(string const & jsonBuffer, map<string, CountryInfo> & id2info); + void LoadCountryCode2File(string const & jsonBuffer, multimap<string, string> & code2file); + + bool SaveCountries(int64_t version, CountriesContainerT const & countries, string & jsonBuffer); +} diff --git a/storage/map_files_downloader.hpp b/storage/map_files_downloader.hpp index ad9224b426..ce0cf2fc1f 100644 --- a/storage/map_files_downloader.hpp +++ b/storage/map_files_downloader.hpp @@ -2,7 +2,6 @@ #include "std/function.hpp" #include "std/string.hpp" - #include "std/utility.hpp" #include "std/vector.hpp" diff --git a/storage/queued_country.cpp b/storage/queued_country.cpp deleted file mode 100644 index 9034370e77..0000000000 --- a/storage/queued_country.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "storage/queued_country.hpp" - -#include "base/assert.hpp" - -namespace storage -{ -QueuedCountry::QueuedCountry(TIndex const & index, TMapOptions opt) - : m_index(index), m_init(opt), m_left(opt), m_current(TMapOptions::ENothing) -{ - ASSERT(GetIndex().IsValid(), ("Only valid countries may be downloaded.")); - ASSERT(m_left != TMapOptions::ENothing, ("Empty file set was requested for downloading.")); - SwitchToNextFile(); -} - -void QueuedCountry::AddOptions(TMapOptions opt) -{ - for (TMapOptions file : {TMapOptions::EMap, TMapOptions::ECarRouting}) - { - if (HasOptions(opt, file) && !HasOptions(m_init, file)) - { - m_init = SetOptions(m_init, file); - m_left = SetOptions(m_left, file); - } - } -} - -void QueuedCountry::RemoveOptions(TMapOptions opt) -{ - for (TMapOptions file : {TMapOptions::EMap, TMapOptions::ECarRouting}) - { - if (HasOptions(opt, file) && HasOptions(m_init, file)) - { - m_init = UnsetOptions(m_init, file); - m_left = UnsetOptions(m_left, file); - } - } - if (HasOptions(opt, m_current)) - m_current = LeastSignificantOption(m_left); -} - -bool QueuedCountry::SwitchToNextFile() -{ - // static_casts are needed here because TMapOptions values are - // actually enum flags (see 3party/enum_flags.hpp) and bitwise - // operators are overloaded for them. - ASSERT(HasOptions(m_left, m_current), - ("Current file (", m_current, ") is not specified in left files (", m_left, ").")); - m_left = UnsetOptions(m_left, m_current); - m_current = LeastSignificantOption(m_left); - return m_current != TMapOptions::ENothing; -} -} // namespace storage diff --git a/storage/queued_country.hpp b/storage/queued_country.hpp deleted file mode 100644 index de0f070273..0000000000 --- a/storage/queued_country.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "storage/index.hpp" -#include "platform/country_defines.hpp" - -namespace storage -{ -/// Country queued for downloading. -class QueuedCountry -{ -public: - QueuedCountry(TIndex const & index, TMapOptions opt); - - void AddOptions(TMapOptions opt); - void RemoveOptions(TMapOptions opt); - bool SwitchToNextFile(); - - inline TIndex const & GetIndex() const { return m_index; } - inline TMapOptions GetInitOptions() const { return m_init; } - inline TMapOptions GetCurrentFile() const { return m_current; } - inline TMapOptions GetDownloadedFiles() const { return UnsetOptions(m_init, m_left); } - - inline bool operator==(TIndex const & index) const { return m_index == index; } - -private: - TIndex m_index; - TMapOptions m_init; - TMapOptions m_left; - TMapOptions m_current; -}; -} // namespace storage diff --git a/storage/storage.cpp b/storage/storage.cpp index b9f7e75f58..bad306c873 100644 --- a/storage/storage.cpp +++ b/storage/storage.cpp @@ -4,22 +4,17 @@ #include "defines.hpp" -#include "platform/local_country_file_utils.hpp" #include "platform/platform.hpp" #include "platform/servers_list.hpp" #include "platform/settings.hpp" -#include "coding/file_container.hpp" -#include "coding/file_name_utils.hpp" -#include "coding/file_reader.hpp" #include "coding/file_writer.hpp" -#include "coding/internal/file_data.hpp" +#include "coding/file_reader.hpp" +#include "coding/file_container.hpp" #include "coding/url_encode.hpp" - -#include "platform/local_country_file_utils.hpp" +#include "coding/file_name_utils.hpp" #include "base/logging.hpp" -#include "base/scope_guard.hpp" #include "base/string_utils.hpp" #include "std/algorithm.hpp" @@ -30,844 +25,688 @@ #include "3party/Alohalytics/src/alohalytics.h" using namespace downloader; -using namespace platform; namespace storage { -namespace -{ -template <typename T> -void RemoveIf(vector<T> & v, function<bool(T const & t)> const & p) -{ - v.erase(remove_if(v.begin(), v.end(), p), v.end()); -} + /* + static string ErrorString(DownloadResultT res) + { + switch (res) + { + case EHttpDownloadCantCreateFile: + return "File can't be created. Probably, you have no disk space available or " + "using read-only file system."; + case EHttpDownloadFailed: + return "Download failed due to missing or poor connection. " + "Please, try again later."; + case EHttpDownloadFileIsLocked: + return "Download can't be finished because file is locked. " + "Please, try again after restarting application."; + case EHttpDownloadFileNotFound: + return "Requested file is absent on the server."; + case EHttpDownloadNoConnectionAvailable: + return "No network connection is available."; + case EHttpDownloadOk: + return "Download finished successfully."; + } + return "Unknown error"; + } + */ -uint64_t GetLocalSize(shared_ptr<LocalCountryFile> file, TMapOptions opt) -{ - if (file.get() == nullptr) - return 0; - uint64_t size = 0; - for (TMapOptions bit : {TMapOptions::EMap, TMapOptions::ECarRouting}) + Storage::QueuedCountry::QueuedCountry(Storage const & storage, TIndex const & index, + TMapOptions opt) + : m_index(index), m_init(opt), m_left(opt) { - if (HasOptions(opt, bit)) - size += file->GetSize(bit); + m_pFile = &(storage.CountryByIndex(index).GetFile()); + + // Don't queue files with 0-size on server (empty or absent). + // Downloader has lots of assertions about it. If car routing was + // requested for downloading, try to download it first. + if (HasOptions(m_init, TMapOptions::ECarRouting) && + m_pFile->GetRemoteSize(TMapOptions::ECarRouting) > 0) + { + m_current = TMapOptions::ECarRouting; + } + else + { + m_init = m_current = m_left = TMapOptions::EMap; + } } - return size; -} -uint64_t GetRemoteSize(CountryFile const & file, TMapOptions opt) -{ - uint64_t size = 0; - for (TMapOptions bit : {TMapOptions::EMap, TMapOptions::ECarRouting}) + void Storage::QueuedCountry::AddOptions(TMapOptions opt) { - if (HasOptions(opt, bit)) - size += file.GetRemoteSize(bit); + TMapOptions const arr[] = { TMapOptions::EMap, TMapOptions::ECarRouting }; + for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) + { + if (HasOptions(opt, arr[i]) && !HasOptions(m_init, arr[i])) + { + m_init = SetOptions(m_init, arr[i]); + m_left = SetOptions(m_left, arr[i]); + } + } } - return size; -} -// TODO (@gorshenin): directory where country indexes are stored -// should be abstracted out to LocalCountryIndexes. -void DeleteCountryIndexes(CountryFile const & file) -{ - Platform::FilesList files; - Platform const & platform = GetPlatform(); - string const name = file.GetNameWithoutExt(); - string const path = platform.WritablePathForCountryIndexes(name); - - /// @todo We need correct regexp for any file (not including "." and ".."). - platform.GetFilesByRegExp(path, name + "\\..*", files); - for (auto const & file : files) - my::DeleteFileX(path + file); -} + bool Storage::QueuedCountry::MoveNextFile() + { + if (m_current == m_left) + return false; -class EqualFileName -{ - string const & m_name; + /// if m_current != m_left than we download map and routing + /// routing already downloaded and we need to download map + ASSERT(m_current == TMapOptions::ECarRouting, ()); + m_left = m_current = TMapOptions::EMap; + return true; + } -public: - explicit EqualFileName(string const & name) : m_name(name) {} - bool operator()(SimpleTree<Country> const & node) const + bool Storage::QueuedCountry::Correct(TStatus currentStatus) { - Country const & c = node.Value(); - if (c.GetFilesCount() > 0) - return (c.GetFile().GetNameWithoutExt() == m_name); - else + ASSERT(currentStatus != TStatus::EDownloadFailed, ()); + ASSERT(currentStatus != TStatus::EOutOfMemFailed, ()); + ASSERT(currentStatus != TStatus::EInQueue, ()); + ASSERT(currentStatus != TStatus::EDownloading, ()); + ASSERT(currentStatus != TStatus::EUnknown, ()); + + if (m_init == TMapOptions::EMap && currentStatus == TStatus::EOnDisk) return false; - } -}; -} // namespace -Storage::Storage() : m_downloader(new HttpMapFilesDownloader()), m_currentSlotId(0) -{ - LoadCountriesFile(false /* forceReload */); -} +#ifdef DEBUG + if (currentStatus == TStatus::EOnDiskOutOfDate && m_init == TMapOptions::EMap) + ASSERT(m_pFile->GetFileSize(TMapOptions::ECarRouting) == 0, ()); +#endif -void Storage::Init(TUpdateAfterDownload const & updateFn) { m_updateAfterDownload = updateFn; } + if (HasOptions(m_init, TMapOptions::ECarRouting)) + { + ASSERT(HasOptions(m_init, TMapOptions::EMap), ()); -void Storage::RegisterAllLocalMaps() -{ - m_localFiles.clear(); - m_localFilesForFakeCountries.clear(); + if (currentStatus == TStatus::EOnDisk) + { + if (m_pFile->GetFileSize(TMapOptions::ECarRouting) == 0) + m_init = m_left = m_current = TMapOptions::ECarRouting; + else + return false; + } + } - vector<LocalCountryFile> localFiles; - FindAllLocalMaps(localFiles); + return true; + } - auto compareByCountryAndVersion = [](LocalCountryFile const & lhs, LocalCountryFile const & rhs) + uint64_t Storage::QueuedCountry::GetDownloadSize() const { - if (lhs.GetCountryFile() != rhs.GetCountryFile()) - return lhs.GetCountryFile() < rhs.GetCountryFile(); - return lhs.GetVersion() > rhs.GetVersion(); - }; + return m_pFile->GetRemoteSize(m_current); + } - auto equalByCountry = [](LocalCountryFile const & lhs, LocalCountryFile const & rhs) + LocalAndRemoteSizeT Storage::QueuedCountry::GetFullSize() const { - return lhs.GetCountryFile() == rhs.GetCountryFile(); - }; + LocalAndRemoteSizeT res(0, 0); + TMapOptions const arr[] = { TMapOptions::EMap, TMapOptions::ECarRouting }; + for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) + { + if (HasOptions(m_init, arr[i])) + { + res.first += m_pFile->GetFileSize(arr[i]); + res.second += m_pFile->GetRemoteSize(arr[i]); + } + } - sort(localFiles.begin(), localFiles.end(), compareByCountryAndVersion); + return res; + } - auto i = localFiles.begin(); - while (i != localFiles.end()) + size_t Storage::QueuedCountry::GetFullRemoteSize() const { - auto j = i + 1; - while (j != localFiles.end() && equalByCountry(*i, *j)) + size_t res = 0; + TMapOptions const arr[] = { TMapOptions::EMap, TMapOptions::ECarRouting }; + for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) { - LocalCountryFile & localFile = *j; - LOG(LINFO, ("Removing obsolete", localFile)); - localFile.SyncWithDisk(); - localFile.DeleteFromDisk(TMapOptions::EMapWithCarRouting); - ++j; + if (HasOptions(m_init, arr[i])) + res += m_pFile->GetRemoteSize(arr[i]); } - LocalCountryFile const & localFile = *i; - string const name = localFile.GetCountryFile().GetNameWithoutExt(); - TIndex index = FindIndexByFile(name); - if (index.IsValid()) - RegisterCountryFiles(index, localFile.GetDirectory(), localFile.GetVersion()); - else - RegisterFakeCountryFiles(localFile); - LOG(LINFO, ("Found file:", name, "in directory:", localFile.GetDirectory())); - - i = j; + return res; } -} -void Storage::GetLocalMaps(vector<CountryFile> & maps) -{ - for (auto const & p : m_localFiles) + string Storage::QueuedCountry::GetFileName() const { - TIndex const & index = p.first; - maps.push_back(GetLatestLocalFile(index)->GetCountryFile()); + return m_pFile->GetFileWithExt(m_current); } - for (auto const & p : m_localFilesForFakeCountries) - maps.push_back(p.second->GetCountryFile()); -} -CountriesContainerT const & NodeFromIndex(CountriesContainerT const & root, TIndex const & index) -{ - // complex logic to avoid [] out_of_bounds exceptions - if (index.m_group == TIndex::INVALID || index.m_group >= static_cast<int>(root.SiblingsCount())) - return root; - if (index.m_country == TIndex::INVALID || - index.m_country >= static_cast<int>(root[index.m_group].SiblingsCount())) - { - return root[index.m_group]; - } - if (index.m_region == TIndex::INVALID || - index.m_region >= static_cast<int>(root[index.m_group][index.m_country].SiblingsCount())) + string Storage::QueuedCountry::GetMapFileName() const { - return root[index.m_group][index.m_country]; + return m_pFile->GetFileWithExt(TMapOptions::EMap); } - return root[index.m_group][index.m_country][index.m_region]; -} -Country const & Storage::CountryByIndex(TIndex const & index) const -{ - return NodeFromIndex(m_countries, index).Value(); -} - -void Storage::GetGroupAndCountry(TIndex const & index, string & group, string & country) const -{ - string fName = CountryByIndex(index).GetFile().GetNameWithoutExt(); - CountryInfo::FileName2FullName(fName); - CountryInfo::FullName2GroupAndMap(fName, group, country); -} + Storage::Storage() : m_downloader(new HttpMapFilesDownloader()), m_currentSlotId(0) + { + LoadCountriesFile(false); -size_t Storage::CountriesCount(TIndex const & index) const -{ - return NodeFromIndex(m_countries, index).SiblingsCount(); -} + if (Settings::IsFirstLaunchForDate(121031)) + { + Platform & pl = GetPlatform(); + string const dir = pl.WritableDir(); -string const & Storage::CountryName(TIndex const & index) const -{ - return NodeFromIndex(m_countries, index).Value().Name(); -} + // Delete all: .mwm.downloading; .mwm.downloading2; .mwm.resume; .mwm.resume2 + string const regexp = "\\" DATA_FILE_EXTENSION "\\.(downloading2?$|resume2?$)"; -string const & Storage::CountryFlag(TIndex const & index) const -{ - return NodeFromIndex(m_countries, index).Value().Flag(); -} + Platform::FilesList files; + pl.GetFilesByRegExp(dir, regexp, files); -LocalAndRemoteSizeT Storage::CountrySizeInBytes(TIndex const & index, TMapOptions opt) const -{ - QueuedCountry const * queuedCountry = FindCountryInQueue(index); - shared_ptr<LocalCountryFile> localFile = GetLatestLocalFile(index); - CountryFile const & countryFile = GetCountryFile(index); - if (queuedCountry == nullptr) - { - return LocalAndRemoteSizeT(GetLocalSize(localFile, opt), GetRemoteSize(countryFile, opt)); + for (size_t j = 0; j < files.size(); ++j) + FileWriter::DeleteFileX(dir + files[j]); + } } - LocalAndRemoteSizeT sizes(0, GetRemoteSize(countryFile, opt)); - if (!m_downloader->IsIdle() && IsCountryFirstInQueue(index)) + void Storage::Init(TUpdateAfterDownload const & updateFn) { - sizes.first = m_downloader->GetDownloadingProgress().first + - GetRemoteSize(countryFile, queuedCountry->GetDownloadedFiles()); + m_updateAfterDownload = updateFn; } - return sizes; -} -CountryFile const & Storage::GetCountryFile(TIndex const & index) const -{ - return CountryByIndex(index).GetFile(); -} - -shared_ptr<LocalCountryFile> Storage::GetLatestLocalFile(CountryFile const & countryFile) const -{ - TIndex const index = FindIndexByFile(countryFile.GetNameWithoutExt()); + CountriesContainerT const & NodeFromIndex(CountriesContainerT const & root, TIndex const & index) { - shared_ptr<LocalCountryFile> localFile = GetLatestLocalFile(index); - if (localFile.get()) - return localFile; + // complex logic to avoid [] out_of_bounds exceptions + if (index.m_group == TIndex::INVALID || index.m_group >= static_cast<int>(root.SiblingsCount())) + return root; + else + { + if (index.m_country == TIndex::INVALID || index.m_country >= static_cast<int>(root[index.m_group].SiblingsCount())) + return root[index.m_group]; + if (index.m_region == TIndex::INVALID || index.m_region >= static_cast<int>(root[index.m_group][index.m_country].SiblingsCount())) + return root[index.m_group][index.m_country]; + return root[index.m_group][index.m_country][index.m_region]; + } } + + Country const & Storage::CountryByIndex(TIndex const & index) const { - auto const it = m_localFilesForFakeCountries.find(countryFile); - if (it != m_localFilesForFakeCountries.end()) - return it->second; + return NodeFromIndex(m_countries, index).Value(); } - return shared_ptr<LocalCountryFile>(); -} -shared_ptr<LocalCountryFile> Storage::GetLatestLocalFile(TIndex const & index) const -{ - auto const it = m_localFiles.find(index); - if (it == m_localFiles.end() || it->second.empty()) - return shared_ptr<LocalCountryFile>(); - list<shared_ptr<LocalCountryFile>> const & files = it->second; - shared_ptr<LocalCountryFile> latest = files.front(); - for (shared_ptr<LocalCountryFile> const & file : files) + void Storage::GetGroupAndCountry(TIndex const & index, string & group, string & country) const { - if (file->GetVersion() > latest->GetVersion()) - latest = file; + string fName = CountryByIndex(index).GetFile().GetFileWithoutExt(); + CountryInfo::FileName2FullName(fName); + CountryInfo::FullName2GroupAndMap(fName, group, country); } - return latest; -} -TStatus Storage::CountryStatus(TIndex const & index) const -{ - // Check if we already downloading this country or have it in the queue - if (IsCountryInQueue(index)) + size_t Storage::CountriesCount(TIndex const & index) const { - if (IsCountryFirstInQueue(index)) - return TStatus::EDownloading; - else - return TStatus::EInQueue; + return NodeFromIndex(m_countries, index).SiblingsCount(); } - // Check if this country has failed while downloading. - if (m_failedCountries.count(index) > 0) - return TStatus::EDownloadFailed; - - return TStatus::EUnknown; -} - -TStatus Storage::CountryStatusEx(TIndex const & index) const -{ - return CountryStatusFull(index, CountryStatus(index)); -} - -void Storage::CountryStatusEx(TIndex const & index, TStatus & status, TMapOptions & options) const -{ - status = CountryStatusEx(index); - - if (status == TStatus::EOnDisk || status == TStatus::EOnDiskOutOfDate) + string const & Storage::CountryName(TIndex const & index) const { - options = TMapOptions::EMap; - - shared_ptr<LocalCountryFile> localFile = GetLatestLocalFile(index); - ASSERT(localFile.get(), ("Invariant violation: local file out of sync with disk.")); - if (localFile->OnDisk(TMapOptions::ECarRouting)) - options = SetOptions(options, TMapOptions::ECarRouting); + return NodeFromIndex(m_countries, index).Value().Name(); } -} - -void Storage::DownloadCountry(TIndex const & index, TMapOptions opt) -{ - opt = NormalizeDownloadFileSet(index, opt); - if (opt == TMapOptions::ENothing) - return; - if (QueuedCountry * queuedCountry = FindCountryInQueue(index)) + string const & Storage::CountryFlag(TIndex const & index) const { - queuedCountry->AddOptions(opt); - return; + return NodeFromIndex(m_countries, index).Value().Flag(); } - m_failedCountries.erase(index); - m_queue.push_back(QueuedCountry(index, opt)); - if (m_queue.size() == 1) - DownloadNextCountryFromQueue(); - else - NotifyStatusChanged(index); -} - -void Storage::DeleteCountry(TIndex const & index, TMapOptions opt) -{ - opt = NormalizeDeleteFileSet(opt); - DeleteCountryFiles(index, opt); - DeleteCountryFilesFromDownloader(index, opt); - KickDownloaderAfterDeletionOfCountryFiles(index); - NotifyStatusChanged(index); -} - -void Storage::DeleteCustomCountryVersion(LocalCountryFile const & localFile) -{ - CountryFile const countryFile = localFile.GetCountryFile(); - localFile.DeleteFromDisk(TMapOptions::EMapWithCarRouting); - + string Storage::CountryFileName(TIndex const & index, TMapOptions opt) const { - auto it = m_localFilesForFakeCountries.find(countryFile); - if (it != m_localFilesForFakeCountries.end()) - { - m_localFilesForFakeCountries.erase(it); - return; - } + return QueuedCountry(*this, index, opt).GetFileName(); } - TIndex const index = FindIndexByFile(countryFile.GetNameWithoutExt()); - if (!index.IsValid()) + string const & Storage::CountryFileNameWithoutExt(TIndex const & index) const { - LOG(LERROR, ("Removed files for an unknown country:", localFile)); - return; + return CountryByIndex(index).GetFile().GetFileWithoutExt(); } - MY_SCOPE_GUARD(notifyStatusChanged, bind(&Storage::NotifyStatusChanged, this, index)); - - // If file version equals to current data version, delete from downloader all pending requests for - // the country. - if (localFile.GetVersion() == GetCurrentDataVersion()) - DeleteCountryFilesFromDownloader(index, TMapOptions::EMapWithCarRouting); - auto countryFilesIt = m_localFiles.find(index); - if (countryFilesIt == m_localFiles.end()) + string Storage::MapWithoutExt(string mapFile) { - LOG(LERROR, ("Deleted files of an unregistered country:", localFile)); - return; + string::size_type const pos = mapFile.rfind(DATA_FILE_EXTENSION); + if (pos != string::npos) + mapFile.resize(pos); + return std::move(mapFile); } - auto equalsToLocalFile = [&localFile](shared_ptr<LocalCountryFile> const & rhs) + LocalAndRemoteSizeT Storage::CountrySizeInBytes(TIndex const & index, TMapOptions opt) const { - return localFile == *rhs; - }; - countryFilesIt->second.remove_if(equalsToLocalFile); -} - -void Storage::NotifyStatusChanged(TIndex const & index) -{ - for (CountryObservers const & observer : m_observers) - observer.m_changeCountryFn(index); -} - -void Storage::DownloadNextCountryFromQueue() -{ - if (m_queue.empty()) - return; - - QueuedCountry & queuedCountry = m_queue.front(); - DownloadNextFile(queuedCountry); - - // New status for the country, "Downloading" - NotifyStatusChanged(queuedCountry.GetIndex()); -} - -void Storage::DownloadNextFile(QueuedCountry const & country) -{ - CountryFile const & countryFile = GetCountryFile(country.GetIndex()); + LocalAndRemoteSizeT sizes(0, 0); + QueuedCountry cnt(*this, index, opt); + auto const found = find(m_queue.begin(), m_queue.end(), index); + if (found != m_queue.end()) + { + sizes.second = cnt.GetFullRemoteSize(); + if (!m_downloader->IsIdle() && m_queue.front().GetIndex() == index) + sizes.first = m_downloader->GetDownloadingProgress().first + m_countryProgress.first; + } + else + sizes = cnt.GetFullSize(); - // send Country name for statistics - m_downloader->GetServersList(countryFile.GetNameWithoutExt(), - bind(&Storage::OnServerListDownloaded, this, _1)); -} + return sizes; + } -bool Storage::DeleteFromDownloader(TIndex const & index) -{ - if (!DeleteCountryFilesFromDownloader(index, TMapOptions::EMapWithCarRouting)) - return false; - KickDownloaderAfterDeletionOfCountryFiles(index); - NotifyStatusChanged(index); - return true; -} + TStatus Storage::CountryStatus(TIndex const & index) const + { + // first, check if we already downloading this country or have in in the queue + auto const found = find(m_queue.begin(), m_queue.end(), index); + if (found != m_queue.end()) + { + if (found == m_queue.begin()) + return TStatus::EDownloading; + else + return TStatus::EInQueue; + } -bool Storage::IsDownloadInProgress() const { return !m_queue.empty(); } + // second, check if this country has failed while downloading + if (m_failedCountries.count(index) > 0) + return TStatus::EDownloadFailed; -void Storage::LoadCountriesFile(bool forceReload) -{ - if (forceReload) - m_countries.Clear(); + return TStatus::EUnknown; + } - if (m_countries.SiblingsCount() == 0) + TStatus Storage::CountryStatusEx(TIndex const & index) const { - string json; - ReaderPtr<Reader>(GetPlatform().GetReader(COUNTRIES_FILE)).ReadAsString(json); - m_currentVersion = LoadCountries(json, m_countries); - if (m_currentVersion < 0) - LOG(LERROR, ("Can't load countries file", COUNTRIES_FILE)); + return CountryStatusFull(index, CountryStatus(index)); } -} - -int Storage::Subscribe(TChangeCountryFunction const & change, TProgressFunction const & progress) -{ - CountryObservers obs; - obs.m_changeCountryFn = change; - obs.m_progressFn = progress; - obs.m_slotId = ++m_currentSlotId; + void Storage::CountryStatusEx(TIndex const & index, TStatus & status, TMapOptions & options) const + { + status = CountryStatusEx(index); - m_observers.push_back(obs); + if (status == TStatus::EOnDisk || status == TStatus::EOnDiskOutOfDate) + { + options = TMapOptions::EMap; - return obs.m_slotId; -} + string const fName = QueuedCountry(*this, index, TMapOptions::ECarRouting).GetFileName(); + Platform const & pl = GetPlatform(); + if (pl.IsFileExistsByFullPath(pl.WritablePathForFile(fName))) + options = SetOptions(options, TMapOptions::ECarRouting); + } + } -void Storage::Unsubscribe(int slotId) -{ - for (auto i = m_observers.begin(); i != m_observers.end(); ++i) + void Storage::DownloadCountry(TIndex const & index, TMapOptions opt) { - if (i->m_slotId == slotId) + ASSERT(opt == TMapOptions::EMap || opt == TMapOptions::EMapWithCarRouting, ()); + // check if we already downloading this country + auto const found = find(m_queue.begin(), m_queue.end(), index); + if (found != m_queue.end()) { - m_observers.erase(i); + found->AddOptions(opt); return; } - } -} - -void Storage::OnMapFileDownloadFinished(bool success, - MapFilesDownloader::TProgress const & progress) -{ - if (m_queue.empty()) - return; - QueuedCountry & queuedCountry = m_queue.front(); - TIndex const index = queuedCountry.GetIndex(); + // remove it from failed list + m_failedCountries.erase(index); - Platform & platform = GetPlatform(); - string const path = GetFileDownloadPath(index, queuedCountry.GetCurrentFile()); + // add it into the queue + QueuedCountry cnt(*this, index, opt); + if (!cnt.Correct(CountryStatusWithoutFailed(index))) + return; + m_queue.push_back(cnt); - success = success && platform.IsFileExistsByFullPath(path) && - RegisterDownloadedFile(path, progress.first /* size */, GetCurrentDataVersion()); + // and start download if necessary + if (m_queue.size() == 1) + { + DownloadNextCountryFromQueue(); + } + else + { + // notify about "In Queue" status + NotifyStatusChanged(index); + } + } - if (success && queuedCountry.SwitchToNextFile()) + void Storage::NotifyStatusChanged(TIndex const & index) { - DownloadNextFile(queuedCountry); - return; + for (CountryObservers const & o : m_observers) + o.m_changeCountryFn(index); } + void Storage::DownloadNextCountryFromQueue() { - string optionsName; - switch (queuedCountry.GetInitOptions()) + if (!m_queue.empty()) { - case TMapOptions::ENothing: - optionsName = "Nothing"; - break; - case TMapOptions::EMap: - optionsName = "Map"; - break; - case TMapOptions::ECarRouting: - optionsName = "CarRouting"; - break; - case TMapOptions::EMapWithCarRouting: - optionsName = "MapWithCarRouting"; - break; + QueuedCountry & cnt = m_queue.front(); + + m_countryProgress.first = 0; + m_countryProgress.second = cnt.GetFullRemoteSize(); + + DownloadNextFile(cnt); + + // new status for country, "Downloading" + NotifyStatusChanged(cnt.GetIndex()); } - alohalytics::LogEvent( - "$OnMapDownloadFinished", - alohalytics::TStringMap({{"name", GetCountryFile(index).GetNameWithoutExt()}, - {"status", success ? "ok" : "failed"}, - {"version", strings::to_string(GetCurrentDataVersion())}, - {"option", optionsName}})); } - if (success) + + void Storage::DownloadNextFile(QueuedCountry const & cnt) { - shared_ptr<LocalCountryFile> localFile = GetLocalFile(index, GetCurrentDataVersion()); - ASSERT(localFile.get(), ()); - OnMapDownloadFinished(localFile); + // send Country name for statistics + m_downloader->GetServersList(cnt.GetFileName(), + bind(&Storage::OnServerListDownloaded, this, _1)); } - else + + /* + m2::RectD Storage::CountryBounds(TIndex const & index) const { - OnMapDownloadFailed(); + Country const & country = CountryByIndex(index); + return country.Bounds(); } + */ - m_queue.pop_front(); - - NotifyStatusChanged(index); - - m_downloader->Reset(); - DownloadNextCountryFromQueue(); -} - -void Storage::ReportProgress(TIndex const & idx, pair<int64_t, int64_t> const & p) -{ - for (CountryObservers const & o : m_observers) - o.m_progressFn(idx, p); -} - -void Storage::OnServerListDownloaded(vector<string> const & urls) -{ - // Queue can be empty because countries were deleted from queue. - if (m_queue.empty()) - return; - - QueuedCountry const & queuedCountry = m_queue.front(); - TIndex const & index = queuedCountry.GetIndex(); - TMapOptions const file = queuedCountry.GetCurrentFile(); - - vector<string> fileUrls; - fileUrls.reserve(urls.size()); - for (string const & url : urls) - fileUrls.push_back(GetFileDownloadUrl(url, index, file)); - - string const filePath = GetFileDownloadPath(index, file); - m_downloader->DownloadMapFile(fileUrls, filePath, GetDownloadSize(queuedCountry), - bind(&Storage::OnMapFileDownloadFinished, this, _1, _2), - bind(&Storage::OnMapFileDownloadProgress, this, _1)); -} - -void Storage::OnMapFileDownloadProgress(MapFilesDownloader::TProgress const & progress) -{ - // Queue can be empty because countries were deleted from queue. - if (m_queue.empty()) - return; - - if (!m_observers.empty()) + bool Storage::DeleteFromDownloader(TIndex const & index) { - QueuedCountry & queuedCountry = m_queue.front(); - CountryFile const & countryFile = GetCountryFile(queuedCountry.GetIndex()); - MapFilesDownloader::TProgress p = progress; - p.first += GetRemoteSize(countryFile, queuedCountry.GetDownloadedFiles()); - p.second = GetRemoteSize(countryFile, queuedCountry.GetInitOptions()); - - ReportProgress(m_queue.front().GetIndex(), p); - } -} + // check if we already downloading this country + auto const found = find(m_queue.begin(), m_queue.end(), index); + if (found != m_queue.end()) + { + if (found == m_queue.begin()) + { + // stop download + m_downloader->Reset(); + // remove from the queue + m_queue.erase(found); + // start another download if the queue is not empty + DownloadNextCountryFromQueue(); + } + else + { + // remove from the queue + m_queue.erase(found); + } -bool Storage::RegisterDownloadedFile(string const & path, uint64_t size, int64_t version) -{ - QueuedCountry & queuedCountry = m_queue.front(); - TIndex const & index = queuedCountry.GetIndex(); - uint64_t const expectedSize = GetDownloadSize(queuedCountry); + NotifyStatusChanged(index); + return true; + } - ASSERT_EQUAL(size, expectedSize, ("Downloaded file size mismatch:", size, - "bytes were downloaded,", expectedSize, "bytes expected.")); + return false; + } - CountryFile const countryFile = GetCountryFile(index); - shared_ptr<LocalCountryFile> localFile = GetLocalFile(index, version); - if (localFile.get() == nullptr) - localFile = PreparePlaceForCountryFiles(countryFile, version); - if (localFile.get() == nullptr) + bool Storage::IsDownloadInProgress() const { - LOG(LERROR, ("Local file data structure can't prepared for downloaded file(", path, ").")); - return false; + return !m_queue.empty(); } - if (!my::RenameFileX(path, localFile->GetPath(queuedCountry.GetCurrentFile()))) - return false; - RegisterCountryFiles(localFile); - return true; -} -void Storage::OnMapDownloadFinished(shared_ptr<LocalCountryFile> localFile) -{ - DeleteCountryIndexes(localFile->GetCountryFile()); + void Storage::LoadCountriesFile(bool forceReload) + { + if (forceReload) + m_countries.Clear(); - // Notify framework that all requested files for the country were downloaded. - m_updateAfterDownload(*localFile); -} + if (m_countries.SiblingsCount() == 0) + { + string json; + ReaderPtr<Reader>(GetPlatform().GetReader(COUNTRIES_FILE)).ReadAsString(json); + m_currentVersion = LoadCountries(json, m_countries); + if (m_currentVersion < 0) + LOG(LERROR, ("Can't load countries file", COUNTRIES_FILE)); + } + } -void Storage::OnMapDownloadFailed() -{ - TIndex const & index = m_queue.front().GetIndex(); + int Storage::Subscribe(TChangeCountryFunction const & change, + TProgressFunction const & progress) + { + CountryObservers obs; - // Add country to the failed countries set. - m_failedCountries.insert(index); - m_downloader->Reset(); - DownloadNextCountryFromQueue(); -} + obs.m_changeCountryFn = change; + obs.m_progressFn = progress; + obs.m_slotId = ++m_currentSlotId; -string Storage::GetFileDownloadUrl(string const & baseUrl, TIndex const & index, - TMapOptions file) const -{ - CountryFile const & countryFile = GetCountryFile(index); - return baseUrl + OMIM_OS_NAME "/" + strings::to_string(GetCurrentDataVersion()) + "/" + - UrlEncode(countryFile.GetNameWithExt(file)); -} + m_observers.push_back(obs); -TIndex Storage::FindIndexByFile(string const & name) const -{ - EqualFileName fn(name); + return obs.m_slotId; + } - for (size_t i = 0; i < m_countries.SiblingsCount(); ++i) + void Storage::Unsubscribe(int slotId) { - if (fn(m_countries[i])) - return TIndex(static_cast<int>(i)); - - for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j) + for (auto i = m_observers.begin(); i != m_observers.end(); ++i) { - if (fn(m_countries[i][j])) - return TIndex(static_cast<int>(i), static_cast<int>(j)); - - for (size_t k = 0; k < m_countries[i][j].SiblingsCount(); ++k) + if (i->m_slotId == slotId) { - if (fn(m_countries[i][j][k])) - return TIndex(static_cast<int>(i), static_cast<int>(j), static_cast<int>(k)); + m_observers.erase(i); + return; } } } - return TIndex(); -} + void Storage::OnMapDownloadFinished(bool success, MapFilesDownloader::TProgress const & progress) + { + if (m_queue.empty()) + { + ASSERT ( false, ("queue can't be empty") ); + return; + } -vector<TIndex> Storage::FindAllIndexesByFile(string const & name) const -{ - EqualFileName fn(name); - vector<TIndex> res; + QueuedCountry & cnt = m_queue.front(); + TIndex const index = cnt.GetIndex(); - for (size_t i = 0; i < m_countries.SiblingsCount(); ++i) - { - if (fn(m_countries[i])) - res.emplace_back(static_cast<int>(i)); + bool const downloadHasFailed = !success; + { + string optionName; + switch (cnt.GetInitOptions()) + { + case TMapOptions::ENothing: optionName = "Nothing"; break; + case TMapOptions::EMap: optionName = "Map"; break; + case TMapOptions::ECarRouting: optionName = "CarRouting"; break; + case TMapOptions::EMapWithCarRouting: optionName = "MapWithCarRouting"; break; + } + alohalytics::LogEvent("$OnMapDownloadFinished", + alohalytics::TStringMap({{"name", cnt.GetMapFileName()}, + {"status", downloadHasFailed ? "failed" : "ok"}, + {"version", strings::to_string(GetCurrentDataVersion())}, + {"option", optionName}})); + } - for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j) + if (downloadHasFailed) { - if (fn(m_countries[i][j])) - res.emplace_back(static_cast<int>(i), static_cast<int>(j)); + // add to failed countries set + m_failedCountries.insert(index); + } + else + { + ASSERT_EQUAL(progress.first, progress.second, ()); + ASSERT_EQUAL(progress.first, cnt.GetDownloadSize(), ()); - for (size_t k = 0; k < m_countries[i][j].SiblingsCount(); ++k) + m_countryProgress.first += progress.first; + if (cnt.MoveNextFile()) { - if (fn(m_countries[i][j][k])) - res.emplace_back(static_cast<int>(i), static_cast<int>(j), static_cast<int>(k)); + DownloadNextFile(cnt); + return; } + + // notify framework that downloading is done + m_updateAfterDownload(cnt.GetMapFileName(), cnt.GetInitOptions()); } + + m_queue.pop_front(); + + NotifyStatusChanged(index); + + m_downloader->Reset(); + DownloadNextCountryFromQueue(); } - return res; -} + void Storage::ReportProgress(TIndex const & idx, pair<int64_t, int64_t> const & p) + { + for (CountryObservers const & o : m_observers) + o.m_progressFn(idx, p); + } -void Storage::GetOutdatedCountries(vector<Country const *> & countries) const -{ - for (auto const & p : m_localFiles) + void Storage::OnMapDownloadProgress(MapFilesDownloader::TProgress const & progress) { - TIndex const & index = p.first; - string const name = GetCountryFile(index).GetNameWithoutExt(); - shared_ptr<LocalCountryFile> const & file = GetLatestLocalFile(index); - if (file.get() && file->GetVersion() != GetCurrentDataVersion() && - name != WORLD_COASTS_FILE_NAME && name != WORLD_FILE_NAME) + if (m_queue.empty()) { - countries.push_back(&CountryByIndex(index)); + ASSERT ( false, ("queue can't be empty") ); + return; } - } -} -TStatus Storage::CountryStatusWithoutFailed(TIndex const & index) const -{ - // First, check if we already downloading this country or have in in the queue. - if (!IsCountryInQueue(index)) - return CountryStatusFull(index, TStatus::EUnknown); - return IsCountryFirstInQueue(index) ? TStatus::EDownloading : TStatus::EInQueue; -} + if (!m_observers.empty()) + { + MapFilesDownloader::TProgress p = progress; + p.first += m_countryProgress.first; + p.second = m_countryProgress.second; -TStatus Storage::CountryStatusFull(TIndex const & index, TStatus const status) const -{ - if (status != TStatus::EUnknown) - return status; + ReportProgress(m_queue.front().GetIndex(), p); + } + } - shared_ptr<LocalCountryFile> localFile = GetLatestLocalFile(index); - if (localFile.get() == nullptr || !localFile->OnDisk(TMapOptions::EMap)) - return TStatus::ENotDownloaded; + void Storage::OnServerListDownloaded(vector<string> const & urls) + { + if (m_queue.empty()) + { + ASSERT ( false, ("queue can't be empty") ); + return; + } - CountryFile const & countryFile = GetCountryFile(index); - if (GetRemoteSize(countryFile, TMapOptions::EMap) == 0) - return TStatus::EUnknown; + QueuedCountry const & cnt = m_queue.front(); - if (localFile->GetVersion() != GetCurrentDataVersion()) - return TStatus::EOnDiskOutOfDate; - return TStatus::EOnDisk; -} + vector<string> fileUrls(urls.size()); + // append actual version and file name + string const fileName = cnt.GetFileName(); + for (size_t i = 0; i < urls.size(); ++i) + fileUrls[i] = GetFileDownloadUrl(urls[i], fileName); -TMapOptions Storage::NormalizeDownloadFileSet(TIndex const & index, TMapOptions opt) const -{ - // Car routing files are useless without map files. - if (HasOptions(opt, TMapOptions::ECarRouting)) - opt = SetOptions(opt, TMapOptions::EMap); + string const filePath = GetPlatform().WritablePathForFile(fileName + READY_FILE_EXTENSION); + m_downloader->DownloadMapFile(fileUrls, filePath, cnt.GetDownloadSize(), + bind(&Storage::OnMapDownloadFinished, this, _1, _2), + bind(&Storage::OnMapDownloadProgress, this, _1)); + } - shared_ptr<LocalCountryFile> localCountryFile = GetLatestLocalFile(index); - for (TMapOptions file : {TMapOptions::EMap, TMapOptions::ECarRouting}) + string Storage::GetFileDownloadUrl(string const & baseUrl, string const & fName) const + { + return baseUrl + OMIM_OS_NAME "/" + strings::to_string(m_currentVersion) + "/" + UrlEncode(fName); + } + + namespace + { + class EqualFileName { - // Check whether requested files are on disk and up-to-date. - if (HasOptions(opt, file) && localCountryFile.get() && localCountryFile->OnDisk(file) && - localCountryFile->GetVersion() == GetCurrentDataVersion()) + string const & m_name; + public: + explicit EqualFileName(string const & name) : m_name(name) {} + bool operator()(SimpleTree<Country> const & node) const { - opt = UnsetOptions(opt, file); + Country const & c = node.Value(); + if (c.GetFilesCount() > 0) + return (c.GetFile().GetFileWithoutExt() == m_name); + else + return false; } + }; } - return opt; -} -TMapOptions Storage::NormalizeDeleteFileSet(TMapOptions opt) const -{ - // Car routing files are useless without map files. - if (HasOptions(opt, TMapOptions::EMap)) - opt = SetOptions(opt, TMapOptions::ECarRouting); - return opt; -} + TIndex Storage::FindIndexByFile(string const & name) const + { + EqualFileName fn(name); -QueuedCountry * Storage::FindCountryInQueue(TIndex const & index) -{ - auto it = find(m_queue.begin(), m_queue.end(), index); - return it == m_queue.end() ? nullptr : &*it; -} + for (size_t i = 0; i < m_countries.SiblingsCount(); ++i) + { + if (fn(m_countries[i])) + return TIndex(static_cast<int>(i)); -QueuedCountry const * Storage::FindCountryInQueue(TIndex const & index) const -{ - auto it = find(m_queue.begin(), m_queue.end(), index); - return it == m_queue.end() ? nullptr : &*it; -} + for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j) + { + if (fn(m_countries[i][j])) + return TIndex(static_cast<int>(i), static_cast<int>(j)); + + for (size_t k = 0; k < m_countries[i][j].SiblingsCount(); ++k) + { + if (fn(m_countries[i][j][k])) + return TIndex(static_cast<int>(i), static_cast<int>(j), static_cast<int>(k)); + } + } + } -bool Storage::IsCountryInQueue(TIndex const & index) const -{ - return FindCountryInQueue(index) != nullptr; -} + return TIndex(); + } -bool Storage::IsCountryFirstInQueue(TIndex const & index) const -{ - return !m_queue.empty() && m_queue.front().GetIndex() == index; -} + vector<TIndex> Storage::FindAllIndexesByFile(string const & name) const + { + EqualFileName fn(name); + vector<TIndex> res; -void Storage::SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader) -{ - m_downloader = move(downloader); -} + for (size_t i = 0; i < m_countries.SiblingsCount(); ++i) + { + if (fn(m_countries[i])) + res.emplace_back(static_cast<int>(i)); -shared_ptr<LocalCountryFile> Storage::GetLocalFile(TIndex const & index, int64_t version) const -{ - auto const it = m_localFiles.find(index); - if (it == m_localFiles.end() || it->second.empty()) - return shared_ptr<LocalCountryFile>(); - list<shared_ptr<LocalCountryFile>> const & files = it->second; - for (shared_ptr<LocalCountryFile> const & file : files) - { - if (file->GetVersion() == version) - return file; - } - return shared_ptr<LocalCountryFile>(); -} + for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j) + { + if (fn(m_countries[i][j])) + res.emplace_back(static_cast<int>(i), static_cast<int>(j)); + + for (size_t k = 0; k < m_countries[i][j].SiblingsCount(); ++k) + { + if (fn(m_countries[i][j][k])) + res.emplace_back(static_cast<int>(i), static_cast<int>(j), static_cast<int>(k)); + } + } + } -void Storage::RegisterCountryFiles(shared_ptr<LocalCountryFile> localFile) -{ - CHECK(localFile.get(), ()); - localFile->SyncWithDisk(); - - TIndex const index = FindIndexByFile(localFile->GetCountryFile().GetNameWithoutExt()); - shared_ptr<LocalCountryFile> existingFile = GetLocalFile(index, localFile->GetVersion()); - if (existingFile.get() != nullptr) - ASSERT_EQUAL(localFile.get(), existingFile.get(), ()); - else - m_localFiles[index].push_front(localFile); -} + return res; + } -void Storage::RegisterCountryFiles(TIndex const & index, string const & directory, int64_t version) -{ - shared_ptr<LocalCountryFile> localFile = GetLocalFile(index, version); - if (localFile) - return; + void Storage::GetOutdatedCountries(vector<Country const *> & res) const + { + Platform & pl = GetPlatform(); + Platform::FilesList fList; + pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, fList); - CountryFile const & countryFile = GetCountryFile(index); - localFile = make_shared<LocalCountryFile>(directory, countryFile, version); - RegisterCountryFiles(localFile); -} + for_each(fList.begin(), fList.end(), bind(&my::GetNameWithoutExt, _1)); -void Storage::RegisterFakeCountryFiles(platform::LocalCountryFile const & localFile) -{ - shared_ptr<LocalCountryFile> fakeCountryLocalFile = make_shared<LocalCountryFile>(localFile); - fakeCountryLocalFile->SyncWithDisk(); - m_localFilesForFakeCountries[fakeCountryLocalFile->GetCountryFile()] = fakeCountryLocalFile; -} + fList.erase(remove_if(fList.begin(), fList.end(), [] (string const & t) + { + return (t == WORLD_COASTS_FILE_NAME) || (t == WORLD_FILE_NAME); + }), fList.end()); -void Storage::DeleteCountryFiles(TIndex const & index, TMapOptions opt) -{ - auto const it = m_localFiles.find(index); - if (it == m_localFiles.end()) - return; + fList.erase(remove_if(fList.begin(), fList.end(), [this] (string const & file) + { + return (CountryStatusEx(FindIndexByFile(file)) != TStatus::EOnDiskOutOfDate); + }), fList.end()); - // TODO (@gorshenin): map-only indexes should not be touched when - // routing indexes are removed. - if (!it->second.empty()) - DeleteCountryIndexes(it->second.front()->GetCountryFile()); + for (size_t i = 0; i < fList.size(); ++i) + res.push_back(&CountryByIndex(FindIndexByFile(fList[i]))); + } - list<shared_ptr<platform::LocalCountryFile>> & localFiles = it->second; - for (shared_ptr<LocalCountryFile> & localFile : localFiles) + void Storage::SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader) { - localFile->DeleteFromDisk(opt); - localFile->SyncWithDisk(); - if (localFile->GetFiles() == TMapOptions::ENothing) - localFile.reset(); + m_downloader = move(downloader); } - auto isNull = [](shared_ptr<LocalCountryFile> const & localFile) - { - return !localFile.get(); - }; - localFiles.remove_if(isNull); - if (localFiles.empty()) - m_localFiles.erase(index); -} -bool Storage::DeleteCountryFilesFromDownloader(TIndex const & index, TMapOptions opt) -{ - QueuedCountry * queuedCountry = FindCountryInQueue(index); - if (!queuedCountry) - return false; - if (IsCountryFirstInQueue(index)) + TStatus Storage::CountryStatusWithoutFailed(TIndex const & index) const { - // Abrupt downloading of the current file if it should be removed. - if (HasOptions(opt, queuedCountry->GetCurrentFile())) - m_downloader->Reset(); + // first, check if we already downloading this country or have in in the queue + auto const found = find(m_queue.begin(), m_queue.end(), index); + if (found != m_queue.end()) + { + if (found == m_queue.begin()) + return TStatus::EDownloading; + else + return TStatus::EInQueue; + } + + return CountryStatusFull(index, TStatus::EUnknown); } - queuedCountry->RemoveOptions(opt); - // Remove country from the queue if there's nothing to download. - if (queuedCountry->GetInitOptions() == TMapOptions::ENothing) - m_queue.erase(find(m_queue.begin(), m_queue.end(), index)); - return true; -} + TStatus Storage::CountryStatusFull(TIndex const & index, TStatus const status) const + { + if (status != TStatus::EUnknown) + return status; -void Storage::KickDownloaderAfterDeletionOfCountryFiles(TIndex const & index) -{ - // Do nothing when there're no countries to download or when downloader is busy. - if (m_queue.empty() || !m_downloader->IsIdle()) - return; - if (IsCountryFirstInQueue(index)) - DownloadNextFile(m_queue.front()); - else - DownloadNextCountryFromQueue(); -} + TStatus res = status; + Country const & c = CountryByIndex(index); + LocalAndRemoteSizeT const size = c.Size(TMapOptions::EMap); -uint64_t Storage::GetDownloadSize(QueuedCountry const & queuedCountry) const -{ - CountryFile const & file = GetCountryFile(queuedCountry.GetIndex()); - return GetRemoteSize(file, queuedCountry.GetCurrentFile()); -} + if (size.first == 0) + return TStatus::ENotDownloaded; -string Storage::GetFileDownloadPath(TIndex const & index, TMapOptions file) const -{ - Platform & platform = GetPlatform(); - CountryFile const & countryFile = GetCountryFile(index); - return platform.WritablePathForFile(countryFile.GetNameWithExt(file) + READY_FILE_EXTENSION); + if (size.second == 0) + return TStatus::EUnknown; + + res = TStatus::EOnDisk; + if (size.first != size.second) + { + /// @todo Do better version check, not just size comparison. + + // Additional check for .ready file. + // Use EOnDisk status if it's good, or EOnDiskOutOfDate otherwise. + Platform const & pl = GetPlatform(); + string const fName = c.GetFile().GetFileWithExt(TMapOptions::EMap) + READY_FILE_EXTENSION; + + uint64_t sz = 0; + if (!pl.GetFileSizeByFullPath(pl.WritablePathForFile(fName), sz) || sz != size.second) + res = TStatus::EOnDiskOutOfDate; + } + + return res; + } } -} // namespace storage diff --git a/storage/storage.hpp b/storage/storage.hpp index 0e3b1f1ccb..efdc07f4c6 100644 --- a/storage/storage.hpp +++ b/storage/storage.hpp @@ -3,230 +3,168 @@ #include "storage/country.hpp" #include "storage/index.hpp" #include "storage/map_files_downloader.hpp" -#include "storage/queued_country.hpp" -#include "storage/storage_defines.hpp" #include "storage/storage_defines.hpp" -#include "std/function.hpp" +#include "std/vector.hpp" #include "std/list.hpp" -#include "std/set.hpp" -#include "std/shared_ptr.hpp" #include "std/string.hpp" +#include "std/set.hpp" +#include "std/function.hpp" #include "std/unique_ptr.hpp" -#include "std/vector.hpp" + namespace storage { -/// Can be used to store local maps and/or maps available for download -class Storage -{ - /// We support only one simultaneous request at the moment - unique_ptr<MapFilesDownloader> m_downloader; - - /// stores timestamp for update checks - int64_t m_currentVersion; - - CountriesContainerT m_countries; - - typedef list<QueuedCountry> TQueue; - - /// @todo. It appeared that our application uses m_queue from - /// different threads without any synchronization. To reproduce it - /// just download a map "from the map" on Android. (CountryStatus is - /// called from a different thread.) It's necessary to check if we - /// can call all the methods from a single thread using - /// RunOnUIThread. If not, at least use a syncronization object. - TQueue m_queue; - - /// stores countries whose download has failed recently - typedef set<TIndex> TCountriesSet; - TCountriesSet m_failedCountries; - - map<TIndex, list<shared_ptr<platform::LocalCountryFile>>> m_localFiles; - map<platform::CountryFile, shared_ptr<platform::LocalCountryFile>> m_localFilesForFakeCountries; - - /// used to correctly calculate total country download progress with more than 1 file - /// <current, total> - MapFilesDownloader::TProgress m_countryProgress; - - /// @name Communicate with GUI - //@{ - typedef function<void(TIndex const &)> TChangeCountryFunction; - typedef function<void(TIndex const &, LocalAndRemoteSizeT const &)> TProgressFunction; - - int m_currentSlotId; - - struct CountryObservers + /// Can be used to store local maps and/or maps available for download + class Storage { - TChangeCountryFunction m_changeCountryFn; - TProgressFunction m_progressFn; - int m_slotId; - }; - - typedef list<CountryObservers> ObserversContT; - ObserversContT m_observers; - //@} - - typedef function<void(platform::LocalCountryFile const &)> TUpdateAfterDownload; - - // This function is called each time all files requested for a - // country were successfully downloaded. - TUpdateAfterDownload m_updateAfterDownload; + /// We support only one simultaneous request at the moment + unique_ptr<MapFilesDownloader> m_downloader; - void DownloadNextCountryFromQueue(); + /// stores timestamp for update checks + int64_t m_currentVersion; - void LoadCountriesFile(bool forceReload); + CountriesContainerT m_countries; - void ReportProgress(TIndex const & index, pair<int64_t, int64_t> const & p); + /// store queue for downloading + class QueuedCountry + { + TIndex m_index; + CountryFile const * m_pFile; + TMapOptions m_init, m_left, m_current; - /// Called on the main thread by MapFilesDownloader when list of - /// suitable servers is received. - void OnServerListDownloaded(vector<string> const & urls); + public: + QueuedCountry(Storage const & storage, TIndex const & index, TMapOptions opt); - /// Called on the main thread by MapFilesDownloader when - /// downloading of a map file succeeds/fails. - void OnMapFileDownloadFinished(bool success, MapFilesDownloader::TProgress const & progress); + void AddOptions(TMapOptions opt); + bool MoveNextFile(); + bool Correct(TStatus currentStatus); - /// Periodically called on the main thread by MapFilesDownloader - /// during the downloading process. - void OnMapFileDownloadProgress(MapFilesDownloader::TProgress const & progress); + TIndex const & GetIndex() const { return m_index; } + TMapOptions GetInitOptions() const { return m_init; } + + bool operator== (TIndex const & index) const { return (m_index == index); } + + uint64_t GetDownloadSize() const; + LocalAndRemoteSizeT GetFullSize() const; + size_t GetFullRemoteSize() const; + string GetFileName() const; + string GetMapFileName() const; + }; - bool RegisterDownloadedFile(string const & path, uint64_t size, int64_t version); - void OnMapDownloadFinished(shared_ptr<platform::LocalCountryFile> localFile); - void OnMapDownloadFailed(); + typedef list<QueuedCountry> TQueue; + /// @todo. It appeared that our application uses m_queue from different threads + /// without any synchronization. To reproduce it just download a map "from the map" + /// on Android. (CountryStatus is called from a different thread.) + /// It's necessary to check if we can call all the methods from a single thread using RunOnUIThread. + /// If not, at least use a syncronization object. + TQueue m_queue; - /// Initiates downloading of the next file from the queue. - void DownloadNextFile(QueuedCountry const & country); + /// stores countries which download has failed recently + typedef set<TIndex> TCountriesSet; + TCountriesSet m_failedCountries; -public: - Storage(); + /// used to correctly calculate total country download progress with more than 1 file + /// <current, total> + MapFilesDownloader::TProgress m_countryProgress; - void Init(TUpdateAfterDownload const & updateFn); + /// @name Communicate with GUI + //@{ + typedef function<void (TIndex const &)> TChangeCountryFunction; + typedef function<void (TIndex const &, LocalAndRemoteSizeT const &)> TProgressFunction; - // Finds and registers all map files in maps directory. In the case - // of several versions of the same map keeps only the latest one, others - // are deleted from disk. - // *NOTE* storage will forget all already known local maps. - void RegisterAllLocalMaps(); + int m_currentSlotId; - // Returns list of all local maps, including fake countries. - void GetLocalMaps(vector<platform::CountryFile> & maps); + struct CountryObservers + { + TChangeCountryFunction m_changeCountryFn; + TProgressFunction m_progressFn; + int m_slotId; + }; - /// @return unique identifier that should be used with Unsubscribe function - int Subscribe(TChangeCountryFunction const & change, TProgressFunction const & progress); - void Unsubscribe(int slotId); + typedef list<CountryObservers> ObserversContT; + ObserversContT m_observers; + //@} - Country const & CountryByIndex(TIndex const & index) const; - TIndex FindIndexByFile(string const & name) const; - /// @todo Temporary function to gel all associated indexes for the country file name. - /// Will be removed in future after refactoring. - vector<TIndex> FindAllIndexesByFile(string const & name) const; - void GetGroupAndCountry(TIndex const & index, string & group, string & country) const; + /// @name Communicate with Framework + //@{ + typedef function<void (string const &, TMapOptions)> TUpdateAfterDownload; + TUpdateAfterDownload m_updateAfterDownload; + //@} - size_t CountriesCount(TIndex const & index) const; - string const & CountryName(TIndex const & index) const; - string const & CountryFlag(TIndex const & index) const; + void DownloadNextCountryFromQueue(); - LocalAndRemoteSizeT CountrySizeInBytes(TIndex const & index, TMapOptions opt) const; - platform::CountryFile const & GetCountryFile(TIndex const & index) const; - shared_ptr<platform::LocalCountryFile> GetLatestLocalFile( - platform::CountryFile const & countryFile) const; - shared_ptr<platform::LocalCountryFile> GetLatestLocalFile(TIndex const & index) const; + void LoadCountriesFile(bool forceReload); - /// Fast version, doesn't check if country is out of date - TStatus CountryStatus(TIndex const & index) const; - /// Slow version, but checks if country is out of date - TStatus CountryStatusEx(TIndex const & index) const; - void CountryStatusEx(TIndex const & index, TStatus & status, TMapOptions & options) const; + void ReportProgress(TIndex const & index, pair<int64_t, int64_t> const & p); - /// Puts country denoted by index into the downloader's queue. - /// During downloading process notifies observers about downloading - /// progress and status changes. - void DownloadCountry(TIndex const & index, TMapOptions opt); + /// Called on the main thread by MapFilesDownloader when list of + /// suitable servers is received. + void OnServerListDownloaded(vector<string> const & urls); - /// Removes country files (for all versions) from the device. - /// Notifies observers about country status change. - void DeleteCountry(TIndex const & index, TMapOptions opt); + /// Called on the main thread by MapFilesDownloader when + /// downloading of a map file succeeds/fails. + void OnMapDownloadFinished(bool success, MapFilesDownloader::TProgress const & progress); - /// Removes country files of a particular version from the device. - /// Notifies observers about country status change. - void DeleteCustomCountryVersion(platform::LocalCountryFile const & localFile); + /// Periodically called on the main thread by MapFilesDownloader + /// during the downloading process. + void OnMapDownloadProgress(MapFilesDownloader::TProgress const & progress); - /// \return True iff country denoted by index was successfully - /// deleted from the downloader's queue. - bool DeleteFromDownloader(TIndex const & index); - bool IsDownloadInProgress() const; + /// Initiates downloading of the next file from the queue. + void DownloadNextFile(QueuedCountry const & cnt); - void NotifyStatusChanged(TIndex const & index); + public: + Storage(); - string GetFileDownloadUrl(string const & baseUrl, TIndex const & index, TMapOptions file) const; + void Init(TUpdateAfterDownload const & updateFn); - /// @param[out] res Populated with oudated countries. - void GetOutdatedCountries(vector<Country const *> & countries) const; + /// @return unique identifier that should be used with Unsubscribe function + int Subscribe(TChangeCountryFunction const & change, + TProgressFunction const & progress); + void Unsubscribe(int slotId); - inline int64_t GetCurrentDataVersion() const { return m_currentVersion; } + Country const & CountryByIndex(TIndex const & index) const; + TIndex FindIndexByFile(string const & name) const; + /// @todo Temporary function to gel all associated indexes for the country file name. + /// Will be removed in future after refactoring. + vector<TIndex> FindAllIndexesByFile(string const & name) const; + void GetGroupAndCountry(TIndex const & index, string & group, string & country) const; - void SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader); + size_t CountriesCount(TIndex const & index) const; + string const & CountryName(TIndex const & index) const; + string const & CountryFlag(TIndex const & index) const; -private: - TStatus CountryStatusWithoutFailed(TIndex const & index) const; - TStatus CountryStatusFull(TIndex const & index, TStatus const status) const; + string CountryFileName(TIndex const & index, TMapOptions opt) const; + string const & CountryFileNameWithoutExt(TIndex const & index) const; + /// Removes map file extension. + static string MapWithoutExt(string mapFile); + LocalAndRemoteSizeT CountrySizeInBytes(TIndex const & index, TMapOptions opt) const; - // Modifies file set of requested files - always adds a map file - // when routing file is requested for downloading, but drops all - // already downloaded and up-to-date files. - TMapOptions NormalizeDownloadFileSet(TIndex const & index, TMapOptions opt) const; + /// Fast version, doesn't check if country is out of date + TStatus CountryStatus(TIndex const & index) const; + /// Slow version, but checks if country is out of date + TStatus CountryStatusEx(TIndex const & index) const; + void CountryStatusEx(TIndex const & index, TStatus & status, TMapOptions & options) const; - // Modifies file set of file to deletion - always adds (marks for - // removal) a routing file when map file is marked for deletion. - TMapOptions NormalizeDeleteFileSet(TMapOptions opt) const; + //m2::RectD CountryBounds(TIndex const & index) const; - // Returns a pointer to a country in the downloader's queue. - QueuedCountry * FindCountryInQueue(TIndex const & index); + void DownloadCountry(TIndex const & index, TMapOptions opt); + bool DeleteFromDownloader(TIndex const & index); + bool IsDownloadInProgress() const; - // Returns a pointer to a country in the downloader's queue. - QueuedCountry const * FindCountryInQueue(TIndex const & index) const; + void NotifyStatusChanged(TIndex const & index); - // Returns true when country is in the downloader's queue. - bool IsCountryInQueue(TIndex const & index) const; + string GetFileDownloadUrl(string const & baseUrl, string const & fName) const; - // Returns true when country is first in the downloader's queue. - bool IsCountryFirstInQueue(TIndex const & index) const; + /// @param[out] res Populated with oudated countries. + void GetOutdatedCountries(vector<Country const *> & res) const; - // Returns local country files of a particular version, or wrapped - // nullptr if there're no country files corresponding to the - // version. - shared_ptr<platform::LocalCountryFile> GetLocalFile(TIndex const & index, int64_t version) const; + int64_t GetCurrentDataVersion() const { return m_currentVersion; } - // Tries to register disk files for a real (listed in countries.txt) - // country. If map files of the same version were already - // registered, does nothing. - void RegisterCountryFiles(shared_ptr<platform::LocalCountryFile> localFile); + void SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader); - // Registers disk files for a country. This method must be used only - // for real (listed in counties.txt) countries. - void RegisterCountryFiles(TIndex const & index, string const & directory, int64_t version); - - // Registers disk files for a country. This method must be used only - // for custom (made by user) map files. - void RegisterFakeCountryFiles(platform::LocalCountryFile const & localFile); - - // Removes disk files for all versions of a country. - void DeleteCountryFiles(TIndex const & index, TMapOptions opt); - - // Removes country files from downloader. - bool DeleteCountryFilesFromDownloader(TIndex const & index, TMapOptions opt); - - // Resumes possibly cancelled downloading of countries after - // deletion of country files. - void KickDownloaderAfterDeletionOfCountryFiles(TIndex const & index); - - // Returns download size of the currently downloading file for the - // queued country. - uint64_t GetDownloadSize(QueuedCountry const & queuedCountry) const; - - // Returns a path to a place on disk downloader can use for - // downloaded files. - string GetFileDownloadPath(TIndex const & index, TMapOptions file) const; -}; -} // storage + private: + TStatus CountryStatusWithoutFailed(TIndex const & index) const; + TStatus CountryStatusFull(TIndex const & index, TStatus const status) const; + }; +} diff --git a/storage/storage.pro b/storage/storage.pro index 5cd9da9f8a..ba4d116a3e 100644 --- a/storage/storage.pro +++ b/storage/storage.pro @@ -18,7 +18,6 @@ HEADERS += \ http_map_files_downloader.hpp \ index.hpp \ map_files_downloader.hpp \ - queued_country.hpp \ simple_tree.hpp \ storage.hpp \ storage_defines.hpp \ @@ -29,6 +28,5 @@ SOURCES += \ country_info.cpp \ http_map_files_downloader.cpp \ index.cpp \ - queued_country.cpp \ storage.cpp \ storage_defines.cpp \ diff --git a/storage/storage_defines.hpp b/storage/storage_defines.hpp index 901ecc10d0..5aa9df921b 100644 --- a/storage/storage_defines.hpp +++ b/storage/storage_defines.hpp @@ -22,4 +22,4 @@ namespace storage string DebugPrint(TStatus status); typedef pair<uint64_t, uint64_t> LocalAndRemoteSizeT; - } // namespace storage +} diff --git a/storage/storage_tests/fake_map_files_downloader.hpp b/storage/storage_tests/fake_map_files_downloader.hpp index cb69bcb2fa..ae544db595 100644 --- a/storage/storage_tests/fake_map_files_downloader.hpp +++ b/storage/storage_tests/fake_map_files_downloader.hpp @@ -18,7 +18,6 @@ class FakeMapFilesDownloader : public MapFilesDownloader { public: FakeMapFilesDownloader(TaskRunner & taskRunner); - virtual ~FakeMapFilesDownloader(); // MapFilesDownloader overrides: diff --git a/storage/storage_tests/queued_country_tests.cpp b/storage/storage_tests/queued_country_tests.cpp deleted file mode 100644 index 01634a6bcf..0000000000 --- a/storage/storage_tests/queued_country_tests.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "testing/testing.hpp" - -#include "storage/queued_country.hpp" -#include "storage/storage.hpp" - -namespace storage -{ -UNIT_TEST(QueuedCountry_AddOptions) -{ - Storage storage; - TIndex const index = storage.FindIndexByFile("USA_Georgia"); - QueuedCountry country(index, TMapOptions::ECarRouting); - - TEST_EQUAL(index, country.GetIndex(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetCurrentFile(), ()); - - country.AddOptions(TMapOptions::EMap); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetCurrentFile(), ()); - - TEST(country.SwitchToNextFile(), ()); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetCurrentFile(), ()); - - TEST(!country.SwitchToNextFile(), ()); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetCurrentFile(), ()); -} - -UNIT_TEST(QueuedCountry_RemoveOptions) -{ - Storage storage; - TIndex const index = storage.FindIndexByFile("USA_Georgia"); - - { - QueuedCountry country(index, TMapOptions::EMapWithCarRouting); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetDownloadedFiles(), ()); - - country.RemoveOptions(TMapOptions::EMap); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetDownloadedFiles(), ()); - - country.RemoveOptions(TMapOptions::ECarRouting); - TEST_EQUAL(TMapOptions::ENothing, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetDownloadedFiles(), ()); - } - - { - QueuedCountry country(index, TMapOptions::EMapWithCarRouting); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetDownloadedFiles(), ()); - - country.SwitchToNextFile(); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetDownloadedFiles(), ()); - - country.RemoveOptions(TMapOptions::ECarRouting); - TEST_EQUAL(TMapOptions::EMap, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetDownloadedFiles(), ()); - } - - { - QueuedCountry country(index, TMapOptions::EMapWithCarRouting); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetDownloadedFiles(), ()); - - country.SwitchToNextFile(); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetDownloadedFiles(), ()); - - country.RemoveOptions(TMapOptions::EMap); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetDownloadedFiles(), ()); - - country.SwitchToNextFile(); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetInitOptions(), ()); - TEST_EQUAL(TMapOptions::ENothing, country.GetCurrentFile(), ()); - TEST_EQUAL(TMapOptions::ECarRouting, country.GetDownloadedFiles(), ()); - } -} - -UNIT_TEST(QueuedCountry_Bits) -{ - Storage storage; - TIndex const index = storage.FindIndexByFile("USA_Georgia"); - QueuedCountry country(index, TMapOptions::EMapWithCarRouting); - TEST_EQUAL(TMapOptions::ENothing, country.GetDownloadedFiles(), ()); - - TEST(country.SwitchToNextFile(), ()); - TEST_EQUAL(TMapOptions::EMap, country.GetDownloadedFiles(), ()); - - TEST(!country.SwitchToNextFile(), ()); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, country.GetDownloadedFiles(), ()); -} -} // namespace storage diff --git a/storage/storage_tests/storage_tests.cpp b/storage/storage_tests/storage_tests.cpp index 9bc206024c..60d795d4c7 100644 --- a/storage/storage_tests/storage_tests.cpp +++ b/storage/storage_tests/storage_tests.cpp @@ -5,9 +5,6 @@ #include "storage/storage_tests/fake_map_files_downloader.hpp" #include "storage/storage_tests/task_runner.hpp" -#include "platform/country_file.hpp" -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" #include "platform/platform.hpp" #include "coding/file_name_utils.hpp" @@ -17,73 +14,67 @@ #include "defines.hpp" #include "base/scope_guard.hpp" -#include "base/string_utils.hpp" #include "std/bind.hpp" -#include "std/map.hpp" #include "std/unique_ptr.hpp" -#include "std/vector.hpp" -using namespace platform; using namespace storage; namespace { -// This class checks steps Storage::DownloadMap() performs to download a map. class CountryDownloaderChecker { public: - CountryDownloaderChecker(Storage & storage, TIndex const & index, TMapOptions files, - vector<TStatus> const & transitionList) + CountryDownloaderChecker(Storage & storage, string const & countryFileName, TMapOptions files) : m_storage(storage), - m_index(index), - m_countryFile(storage.GetCountryFile(m_index)), + m_index(m_storage.FindIndexByFile(countryFileName)), m_files(files), + m_lastStatus(TStatus::ENotDownloaded), m_bytesDownloaded(0), m_totalBytesToDownload(0), - m_slot(0), - m_currStatus(0), - m_transitionList(transitionList) + m_slot(0) { m_slot = m_storage.Subscribe( bind(&CountryDownloaderChecker::OnCountryStatusChanged, this, _1), bind(&CountryDownloaderChecker::OnCountryDownloadingProgress, this, _1, _2)); - TEST(m_index.IsValid(), (m_countryFile)); - TEST(!m_transitionList.empty(), (m_countryFile)); + CHECK(m_index.IsValid(), ()); } void StartDownload() { - TEST_EQUAL(0, m_currStatus, (m_countryFile)); - TEST_LESS(m_currStatus, m_transitionList.size(), (m_countryFile)); - TEST_EQUAL(m_transitionList[m_currStatus], m_storage.CountryStatusEx(m_index), - (m_countryFile)); + CHECK_EQUAL(m_lastStatus, m_storage.CountryStatusEx(m_index), ()); m_storage.DownloadCountry(m_index, m_files); } virtual ~CountryDownloaderChecker() { - TEST_EQUAL(m_currStatus + 1, m_transitionList.size(), (m_countryFile)); m_storage.Unsubscribe(m_slot); + + CHECK_EQUAL(TStatus::EOnDisk, m_lastStatus, ()); + CHECK_EQUAL(m_bytesDownloaded, m_totalBytesToDownload, ()); + + LocalAndRemoteSizeT localAndRemoteSize = m_storage.CountrySizeInBytes(m_index, m_files); + CHECK_EQUAL(m_bytesDownloaded, localAndRemoteSize.first, ()); + CHECK_EQUAL(m_totalBytesToDownload, localAndRemoteSize.second, ()); } +protected: + virtual void CheckStatusTransition(TStatus oldStatus, TStatus newStatus) const = 0; + private: void OnCountryStatusChanged(TIndex const & index) { if (index != m_index) return; + TStatus status = m_storage.CountryStatusEx(m_index); - TStatus const nextStatus = m_storage.CountryStatusEx(m_index); - LOG(LINFO, (m_countryFile, "status transition: from", m_transitionList[m_currStatus], "to", - nextStatus)); - TEST_LESS(m_currStatus + 1, m_transitionList.size(), (m_countryFile)); - TEST_EQUAL(nextStatus, m_transitionList[m_currStatus + 1], (m_countryFile)); - ++m_currStatus; - if (m_transitionList[m_currStatus] == TStatus::EDownloading) + CheckStatusTransition(m_lastStatus, status); + if (status == TStatus::EDownloading) { LocalAndRemoteSizeT localAndRemoteSize = m_storage.CountrySizeInBytes(m_index, m_files); m_totalBytesToDownload = localAndRemoteSize.second; } + m_lastStatus = status; } void OnCountryDownloadingProgress(TIndex const & index, LocalAndRemoteSizeT const & progress) @@ -91,410 +82,185 @@ private: if (index != m_index) return; - LOG(LINFO, (m_countryFile, "downloading progress:", progress)); - - TEST_GREATER(progress.first, m_bytesDownloaded, (m_countryFile)); + CHECK_GREATER(progress.first, m_bytesDownloaded, ()); m_bytesDownloaded = progress.first; - TEST_LESS_OR_EQUAL(m_bytesDownloaded, m_totalBytesToDownload, (m_countryFile)); + CHECK_LESS_OR_EQUAL(m_bytesDownloaded, m_totalBytesToDownload, ()); LocalAndRemoteSizeT localAndRemoteSize = m_storage.CountrySizeInBytes(m_index, m_files); - TEST_EQUAL(m_totalBytesToDownload, localAndRemoteSize.second, (m_countryFile)); + CHECK_EQUAL(m_totalBytesToDownload, localAndRemoteSize.second, ()); } Storage & m_storage; TIndex const m_index; - CountryFile const m_countryFile; + TMapOptions const m_files; + TStatus m_lastStatus; int64_t m_bytesDownloaded; int64_t m_totalBytesToDownload; int m_slot; - - size_t m_currStatus; - vector<TStatus> m_transitionList; }; // Checks following state transitions: // NotDownloaded -> Downloading -> OnDisk. -unique_ptr<CountryDownloaderChecker> AbsentCountryDownloaderChecker(Storage & storage, - TIndex const & index, - TMapOptions files) -{ - return make_unique<CountryDownloaderChecker>( - storage, index, files, - vector<TStatus>{TStatus::ENotDownloaded, TStatus::EDownloading, TStatus::EOnDisk}); -} - -// Checks following state transitions: -// OnDisk -> Downloading -> OnDisk. -unique_ptr<CountryDownloaderChecker> PresentCountryDownloaderChecker(Storage & storage, - TIndex const & index, - TMapOptions files) -{ - return make_unique<CountryDownloaderChecker>( - storage, index, files, - vector<TStatus>{TStatus::EOnDisk, TStatus::EDownloading, TStatus::EOnDisk}); -} - -// Checks following state transitions: -// NotDownloaded -> InQueue -> Downloading -> OnDisk. -unique_ptr<CountryDownloaderChecker> QueuedCountryDownloaderChecker(Storage & storage, - TIndex const & index, - TMapOptions files) -{ - return make_unique<CountryDownloaderChecker>( - storage, index, files, vector<TStatus>{TStatus::ENotDownloaded, TStatus::EInQueue, - TStatus::EDownloading, TStatus::EOnDisk}); -} - -// Checks following state transitions: -// NotDownloaded -> Downloading -> NotDownloaded. -unique_ptr<CountryDownloaderChecker> CancelledCountryDownloaderChecker(Storage & storage, - TIndex const & index, - TMapOptions files) +class AbsentCountryDownloaderChecker : public CountryDownloaderChecker { - return make_unique<CountryDownloaderChecker>( - storage, index, files, - vector<TStatus>{TStatus::ENotDownloaded, TStatus::EDownloading, TStatus::ENotDownloaded}); -} +public: + AbsentCountryDownloaderChecker(Storage & storage, string const & countryFileName, + TMapOptions files) + : CountryDownloaderChecker(storage, countryFileName, files) + { + } -void OnCountryDownloaded(LocalCountryFile const & localFile) -{ - LOG(LINFO, ("OnCountryDownloaded:", localFile)); -} + ~AbsentCountryDownloaderChecker() override = default; -shared_ptr<LocalCountryFile> CreateDummyMapFile(CountryFile const & countryFile, int64_t version, - size_t size) -{ - shared_ptr<LocalCountryFile> localFile = - platform::PreparePlaceForCountryFiles(countryFile, version); - TEST(localFile.get(), ("Can't prepare place for", countryFile, "(version ", version, ")")); +protected: + void CheckStatusTransition(TStatus oldStatus, TStatus newStatus) const override { - string const zeroes(size, '\0'); - FileWriter writer(localFile->GetPath(TMapOptions::EMap)); - writer.Write(zeroes.data(), zeroes.size()); + switch (newStatus) + { + case TStatus::EDownloading: + CHECK_EQUAL(oldStatus, TStatus::ENotDownloaded, + ("It's only possible to move from NotDownloaded to Downloading.")); + break; + case TStatus::EOnDisk: + CHECK_EQUAL(oldStatus, TStatus::EDownloading, + ("It's only possible to move from Downloading to OnDisk.")); + break; + default: + CHECK(false, ("Unknown state change: from", oldStatus, "to", newStatus)); + } } - localFile->SyncWithDisk(); - TEST_EQUAL(TMapOptions::EMap, localFile->GetFiles(), ()); - TEST_EQUAL(size, localFile->GetSize(TMapOptions::EMap), ()); - return localFile; -} +}; -class CountryStatusChecker +// Checks following state transitions: +// NotDownloaded -> InQueue -> Downloading -> OnDisk. +class QueuedCountryDownloaderChecker : public CountryDownloaderChecker { public: - CountryStatusChecker(Storage & storage, TIndex const & index, TStatus status) - : m_storage(storage), m_index(index), m_status(status), m_triggered(false) + QueuedCountryDownloaderChecker(Storage & storage, string const & countryFileName, + TMapOptions files) + : CountryDownloaderChecker(storage, countryFileName, files) { - m_slot = m_storage.Subscribe( - bind(&CountryStatusChecker::OnCountryStatusChanged, this, _1), - bind(&CountryStatusChecker::OnCountryDownloadingProgress, this, _1, _2)); } - ~CountryStatusChecker() - { - TEST(m_triggered, ("Status checker wasn't triggered.")); - m_storage.Unsubscribe(m_slot); - } + ~QueuedCountryDownloaderChecker() override = default; -private: - void OnCountryStatusChanged(TIndex const & index) +protected: + void CheckStatusTransition(TStatus oldStatus, TStatus newStatus) const override { - if (index != m_index) - return; - TEST(!m_triggered, ("Status checker can be triggered only once.")); - TStatus status = m_storage.CountryStatusEx(m_index); - TEST_EQUAL(m_status, status, ()); - m_triggered = true; - } - - void OnCountryDownloadingProgress(TIndex const & /* index */, - LocalAndRemoteSizeT const & /* progress */) - { - TEST(false, ("Unexpected country downloading progress.")); + switch (newStatus) + { + case TStatus::EInQueue: + CHECK_EQUAL(oldStatus, TStatus::ENotDownloaded, + ("It's only possible to move from NotDownloaded to InQueue.")); + break; + case TStatus::EDownloading: + CHECK_EQUAL(oldStatus, TStatus::EInQueue, + ("It's only possible to move from InQueue to Downloading.")); + break; + case TStatus::EOnDisk: + CHECK_EQUAL(oldStatus, TStatus::EDownloading, + ("It's only possible to move from Downloading to OnDisk.")); + break; + default: + CHECK(false, ("Unknown state change: from", oldStatus, "to", newStatus)); + } } - - Storage & m_storage; - TIndex const & m_index; - TStatus m_status; - bool m_triggered; - int m_slot; }; -void InitStorage(Storage & storage, TaskRunner & runner) +// Removes country's files that can be created during and after downloading. +void CleanupCountryFiles(string const & countryFileName) { - storage.Init(&OnCountryDownloaded); - storage.RegisterAllLocalMaps(); - storage.SetDownloaderForTesting(make_unique<FakeMapFilesDownloader>(runner)); -} -} // namespace + Platform & platform = GetPlatform(); -UNIT_TEST(StorageTest_Smoke) -{ - Storage storage; + string const localMapFile = + my::JoinFoldersToPath(platform.WritableDir(), countryFileName + DATA_FILE_EXTENSION); + my::DeleteFileX(localMapFile); + my::DeleteFileX(localMapFile + READY_FILE_EXTENSION); - TIndex const usaGeorgiaIndex = storage.FindIndexByFile("USA_Georgia"); - TEST(usaGeorgiaIndex.IsValid(), ()); - CountryFile usaGeorgiaFile = storage.GetCountryFile(usaGeorgiaIndex); - TEST_EQUAL(usaGeorgiaFile.GetNameWithExt(TMapOptions::EMap), "USA_Georgia" DATA_FILE_EXTENSION, - ()); - - TIndex const georgiaIndex = storage.FindIndexByFile("Georgia"); - TEST(georgiaIndex.IsValid(), ()); - CountryFile georgiaFile = storage.GetCountryFile(georgiaIndex); - TEST_EQUAL(georgiaFile.GetNameWithExt(TMapOptions::ECarRouting), - "Georgia" DATA_FILE_EXTENSION ROUTING_FILE_EXTENSION, ()); - - TEST_NOT_EQUAL(usaGeorgiaIndex, georgiaIndex, ()); + string const localRoutingFile = localMapFile + ROUTING_FILE_EXTENSION; + my::DeleteFileX(localRoutingFile); + my::DeleteFileX(localRoutingFile + READY_FILE_EXTENSION); } -UNIT_TEST(StorageTest_SingleCountryDownloading) +void OnCountryDownloaded(string const & mapFileName, TMapOptions files) { - Storage storage; - TaskRunner runner; - InitStorage(storage, runner); + Platform & platform = GetPlatform(); - TIndex const azerbaijanIndex = storage.FindIndexByFile("Azerbaijan"); - TEST(azerbaijanIndex.IsValid(), ()); + string const localMapFile = my::JoinFoldersToPath(platform.WritableDir(), mapFileName); + string const localRoutingFile = localMapFile + ROUTING_FILE_EXTENSION; - CountryFile azerbaijanFile = storage.GetCountryFile(azerbaijanIndex); - storage.DeleteCountry(azerbaijanIndex, TMapOptions::EMapWithCarRouting); - - { - MY_SCOPE_GUARD(cleanupCountryFiles, - bind(&Storage::DeleteCountry, &storage, azerbaijanIndex, TMapOptions::EMap)); - unique_ptr<CountryDownloaderChecker> checker = - AbsentCountryDownloaderChecker(storage, azerbaijanIndex, TMapOptions::EMapWithCarRouting); - checker->StartDownload(); - runner.Run(); - } - - { - MY_SCOPE_GUARD(cleanupCountryFiles, bind(&Storage::DeleteCountry, &storage, azerbaijanIndex, - TMapOptions::EMapWithCarRouting)); - unique_ptr<CountryDownloaderChecker> checker = - AbsentCountryDownloaderChecker(storage, azerbaijanIndex, TMapOptions::EMapWithCarRouting); - checker->StartDownload(); - runner.Run(); - } + if (HasOptions(files, TMapOptions::EMap)) + CHECK(my::RenameFileX(localMapFile + READY_FILE_EXTENSION, localMapFile), ()); + if (HasOptions(files, TMapOptions::ECarRouting)) + CHECK(my::RenameFileX(localRoutingFile + READY_FILE_EXTENSION, localRoutingFile), ()); } -UNIT_TEST(StorageTest_TwoCountriesDownloading) -{ - Storage storage; - TaskRunner runner; - InitStorage(storage, runner); - - TIndex const uruguayIndex = storage.FindIndexByFile("Uruguay"); - TEST(uruguayIndex.IsValid(), ()); - storage.DeleteCountry(uruguayIndex, TMapOptions::EMap); - MY_SCOPE_GUARD(cleanupUruguayFiles, - bind(&Storage::DeleteCountry, &storage, uruguayIndex, TMapOptions::EMap)); - - TIndex const venezuelaIndex = storage.FindIndexByFile("Venezuela"); - TEST(venezuelaIndex.IsValid(), ()); - storage.DeleteCountry(venezuelaIndex, TMapOptions::EMapWithCarRouting); - MY_SCOPE_GUARD(cleanupVenezuelaFiles, bind(&Storage::DeleteCountry, &storage, venezuelaIndex, - TMapOptions::EMapWithCarRouting)); - - unique_ptr<CountryDownloaderChecker> uruguayChecker = - AbsentCountryDownloaderChecker(storage, uruguayIndex, TMapOptions::EMap); - unique_ptr<CountryDownloaderChecker> venezuelaChecker = - QueuedCountryDownloaderChecker(storage, venezuelaIndex, TMapOptions::EMapWithCarRouting); - uruguayChecker->StartDownload(); - venezuelaChecker->StartDownload(); - runner.Run(); -} - -UNIT_TEST(StorageTest_DeleteTwoVersionsOfTheSameCountry) -{ - Storage storage; - storage.Init(&OnCountryDownloaded); - storage.RegisterAllLocalMaps(); - - TIndex const index = storage.FindIndexByFile("Azerbaijan"); - TEST(index.IsValid(), ()); - CountryFile const countryFile = storage.GetCountryFile(index); - - storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting); - shared_ptr<LocalCountryFile> latestLocalFile = storage.GetLatestLocalFile(index); - TEST(!latestLocalFile.get(), ("Country wasn't deleted from disk.")); - TEST_EQUAL(TStatus::ENotDownloaded, storage.CountryStatusEx(index), ()); - - shared_ptr<LocalCountryFile> localFileV1 = - CreateDummyMapFile(countryFile, 1 /* version */, 1024 /* size */); - storage.RegisterAllLocalMaps(); - latestLocalFile = storage.GetLatestLocalFile(index); - TEST(latestLocalFile.get(), ("Created map file wasn't found by storage.")); - TEST_EQUAL(latestLocalFile->GetVersion(), localFileV1->GetVersion(), ()); - TEST_EQUAL(TStatus::EOnDiskOutOfDate, storage.CountryStatusEx(index), ()); - - shared_ptr<LocalCountryFile> localFileV2 = - CreateDummyMapFile(countryFile, 2 /* version */, 2048 /* size */); - storage.RegisterAllLocalMaps(); - latestLocalFile = storage.GetLatestLocalFile(index); - TEST(latestLocalFile.get(), ("Created map file wasn't found by storage.")); - TEST_EQUAL(latestLocalFile->GetVersion(), localFileV2->GetVersion(), ()); - TEST_EQUAL(TStatus::EOnDiskOutOfDate, storage.CountryStatusEx(index), ()); - - storage.DeleteCountry(index, TMapOptions::EMap); - - localFileV1->SyncWithDisk(); - TEST_EQUAL(TMapOptions::ENothing, localFileV1->GetFiles(), ()); - - localFileV2->SyncWithDisk(); - TEST_EQUAL(TMapOptions::ENothing, localFileV2->GetFiles(), ()); - - TEST_EQUAL(TStatus::ENotDownloaded, storage.CountryStatusEx(index), ()); -} +} // namespace -UNIT_TEST(StorageTest_DownloadCountryAndDeleteRoutingOnly) +UNIT_TEST(StorageTest_Smoke) { - Storage storage; - TaskRunner runner; - InitStorage(storage, runner); - - TIndex const index = storage.FindIndexByFile("Azerbaijan"); - TEST(index.IsValid(), ()); - storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting); - - { - unique_ptr<CountryDownloaderChecker> checker = - AbsentCountryDownloaderChecker(storage, index, TMapOptions::EMapWithCarRouting); - checker->StartDownload(); - runner.Run(); - } + Storage st; - // Delete routing file only and check that latest local file wasn't changed. - shared_ptr<LocalCountryFile> localFileA = storage.GetLatestLocalFile(index); - TEST(localFileA.get(), ()); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, localFileA->GetFiles(), ()); + TIndex const i1 = st.FindIndexByFile("USA_Georgia"); + TEST(i1.IsValid(), ()); + TEST_EQUAL(st.CountryFileName(i1, TMapOptions::EMap), "USA_Georgia" DATA_FILE_EXTENSION, ()); - storage.DeleteCountry(index, TMapOptions::ECarRouting); - - shared_ptr<LocalCountryFile> localFileB = storage.GetLatestLocalFile(index); - TEST(localFileB.get(), ()); - TEST_EQUAL(localFileA.get(), localFileB.get(), (*localFileA, *localFileB)); - TEST_EQUAL(TMapOptions::EMap, localFileB->GetFiles(), ()); + TIndex const i2 = st.FindIndexByFile("Georgia"); + TEST(i2.IsValid(), ()); + TEST_EQUAL(st.CountryFileName(i2, TMapOptions::ECarRouting), + "Georgia" DATA_FILE_EXTENSION ROUTING_FILE_EXTENSION, ()); - storage.DeleteCountry(index, TMapOptions::EMap); - shared_ptr<LocalCountryFile> localFileC = storage.GetLatestLocalFile(index); - TEST(!localFileC.get(), (*localFileC)); + TEST_NOT_EQUAL(i1, i2, ()); } -UNIT_TEST(StorageTest_DownloadMapAndRoutingSeparately) +UNIT_TEST(StorageTest_SingleCountryDownloading) { - Storage storage; - TaskRunner runner; - InitStorage(storage, runner); - - TIndex const index = storage.FindIndexByFile("Azerbaijan"); - TEST(index.IsValid(), ()); - storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting); + string const azerbaijanFileName = "Azerbaijan"; + CleanupCountryFiles(azerbaijanFileName); - // Download map file only. - { - unique_ptr<CountryDownloaderChecker> checker = - AbsentCountryDownloaderChecker(storage, index, TMapOptions::EMap); - checker->StartDownload(); - runner.Run(); - } - - shared_ptr<LocalCountryFile> localFileA = storage.GetLatestLocalFile(index); - TEST(localFileA.get(), ()); - TEST_EQUAL(TMapOptions::EMap, localFileA->GetFiles(), ()); - - // Download routing file in addition to exising map file. - { - unique_ptr<CountryDownloaderChecker> checker = - PresentCountryDownloaderChecker(storage, index, TMapOptions::ECarRouting); - checker->StartDownload(); - runner.Run(); - } + Storage storage; + storage.Init(&OnCountryDownloaded); - shared_ptr<LocalCountryFile> localFileB = storage.GetLatestLocalFile(index); - TEST(localFileB.get(), ()); - TEST_EQUAL(localFileA.get(), localFileB.get(), (*localFileA, *localFileB)); - TEST_EQUAL(TMapOptions::EMapWithCarRouting, localFileB->GetFiles(), ()); + TaskRunner taskRunner; + storage.SetDownloaderForTesting(make_unique<FakeMapFilesDownloader>(taskRunner)); - // Delete routing file and check status update. { - CountryStatusChecker checker(storage, index, TStatus::EOnDisk); - storage.DeleteCountry(index, TMapOptions::ECarRouting); + MY_SCOPE_GUARD(cleanupCountryFiles, bind(&CleanupCountryFiles, azerbaijanFileName)); + AbsentCountryDownloaderChecker checker(storage, azerbaijanFileName, TMapOptions::EMap); + checker.StartDownload(); + taskRunner.Run(); } - shared_ptr<LocalCountryFile> localFileC = storage.GetLatestLocalFile(index); - TEST(localFileC.get(), ()); - TEST_EQUAL(localFileB.get(), localFileC.get(), (*localFileB, *localFileC)); - TEST_EQUAL(TMapOptions::EMap, localFileC->GetFiles(), ()); - // Delete map file and check status update. { - CountryStatusChecker checker(storage, index, TStatus::ENotDownloaded); - storage.DeleteCountry(index, TMapOptions::EMap); + MY_SCOPE_GUARD(cleanupCountryFiles, bind(&CleanupCountryFiles, azerbaijanFileName)); + AbsentCountryDownloaderChecker checker(storage, azerbaijanFileName, + TMapOptions::EMapWithCarRouting); + checker.StartDownload(); + taskRunner.Run(); } } -UNIT_TEST(StorageTest_DeletePendingCountry) +UNIT_TEST(StorageTest_TwoCountriesDownloading) { - Storage storage; - TaskRunner runner; - InitStorage(storage, runner); - - TIndex const index = storage.FindIndexByFile("Azerbaijan"); - TEST(index.IsValid(), ()); - storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting); + string const uruguayFileName = "Uruguay"; + string const venezuelaFileName = "Venezuela"; + CleanupCountryFiles(uruguayFileName); + MY_SCOPE_GUARD(cleanupUruguayFiles, bind(&CleanupCountryFiles, uruguayFileName)); - { - unique_ptr<CountryDownloaderChecker> checker = - CancelledCountryDownloaderChecker(storage, index, TMapOptions::EMap); - checker->StartDownload(); - storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting); - runner.Run(); - } -} + CleanupCountryFiles(venezuelaFileName); + MY_SCOPE_GUARD(cleanupVenezuelaFiles, bind(&CleanupCountryFiles, venezuelaFileName)); -UNIT_TEST(StorageTest_DownloadTwoCountriesAndDelete) -{ Storage storage; - TaskRunner runner; - InitStorage(storage, runner); - - TIndex const uruguayIndex = storage.FindIndexByFile("Uruguay"); - TEST(uruguayIndex.IsValid(), ()); - storage.DeleteCountry(uruguayIndex, TMapOptions::EMapWithCarRouting); - MY_SCOPE_GUARD(cleanupUruguayFiles, bind(&Storage::DeleteCountry, &storage, uruguayIndex, - TMapOptions::EMapWithCarRouting)); - - TIndex const venezuelaIndex = storage.FindIndexByFile("Venezuela"); - TEST(venezuelaIndex.IsValid(), ()); - storage.DeleteCountry(venezuelaIndex, TMapOptions::EMapWithCarRouting); - MY_SCOPE_GUARD(cleanupVenezuelaFiles, bind(&Storage::DeleteCountry, &storage, venezuelaIndex, - TMapOptions::EMapWithCarRouting)); + storage.Init(&OnCountryDownloaded); - { - // Map file will be deleted for Uruguay, thus, routing file should also be deleted. Therefore, - // Uruguay should pass through following states: NotDownloaded -> Downloading -> NotDownloaded. - unique_ptr<CountryDownloaderChecker> uruguayChecker = make_unique<CountryDownloaderChecker>( - storage, uruguayIndex, TMapOptions::EMapWithCarRouting, - vector<TStatus>{TStatus::ENotDownloaded, TStatus::EDownloading, TStatus::ENotDownloaded}); - // Only routing file will be deleted for Venezuela, thus, Venezuela should pass through - // following - // states: - // NotDownloaded -> InQueue (Venezuela is added after Uruguay) -> Downloading -> Downloading - // (second notification will be sent after deletion of a routing file) -> OnDisk. - unique_ptr<CountryDownloaderChecker> venezuelaChecker = make_unique<CountryDownloaderChecker>( - storage, venezuelaIndex, TMapOptions::EMapWithCarRouting, - vector<TStatus>{TStatus::ENotDownloaded, TStatus::EInQueue, TStatus::EDownloading, - TStatus::EDownloading, TStatus::EOnDisk}); - uruguayChecker->StartDownload(); - venezuelaChecker->StartDownload(); - storage.DeleteCountry(uruguayIndex, TMapOptions::EMap); - storage.DeleteCountry(venezuelaIndex, TMapOptions::ECarRouting); - runner.Run(); - } - shared_ptr<LocalCountryFile> uruguayFile = storage.GetLatestLocalFile(uruguayIndex); - TEST(!uruguayFile.get(), (*uruguayFile)); + TaskRunner taskRunner; + storage.SetDownloaderForTesting(make_unique<FakeMapFilesDownloader>(taskRunner)); - shared_ptr<LocalCountryFile> venezuelaFile = storage.GetLatestLocalFile(venezuelaIndex); - TEST(venezuelaFile.get(), ()); - TEST_EQUAL(TMapOptions::EMap, venezuelaFile->GetFiles(), ()); + AbsentCountryDownloaderChecker uruguayChecker(storage, uruguayFileName, TMapOptions::EMap); + QueuedCountryDownloaderChecker venezuelaChecker(storage, venezuelaFileName, + TMapOptions::EMapWithCarRouting); + uruguayChecker.StartDownload(); + venezuelaChecker.StartDownload(); + taskRunner.Run(); } diff --git a/storage/storage_tests/storage_tests.pro b/storage/storage_tests/storage_tests.pro index 1f59397d0d..86879502d5 100644 --- a/storage/storage_tests/storage_tests.pro +++ b/storage/storage_tests/storage_tests.pro @@ -21,11 +21,11 @@ HEADERS += \ fake_map_files_downloader.hpp \ task_runner.hpp \ + SOURCES += \ ../../testing/testingmain.cpp \ country_info_test.cpp \ fake_map_files_downloader.cpp \ - queued_country_tests.cpp \ simple_tree_test.cpp \ storage_tests.cpp \ task_runner.cpp \ |