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

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp11
-rw-r--r--android/jni/com/mapswithme/maps/Framework.cpp46
-rw-r--r--drape_head/drape_surface.cpp12
-rw-r--r--generator/generator_tests/check_mwms.cpp16
-rw-r--r--generator/routing_generator.cpp17
-rw-r--r--generator/update_generator.cpp12
-rw-r--r--indexer/index.cpp142
-rw-r--r--indexer/index.hpp83
-rw-r--r--indexer/indexer_tests/index_builder_test.cpp2
-rw-r--r--indexer/indexer_tests/index_test.cpp141
-rw-r--r--indexer/indexer_tests/mwm_set_test.cpp67
-rw-r--r--indexer/mwm_set.cpp130
-rw-r--r--indexer/mwm_set.hpp86
-rw-r--r--integration_tests/osrm_test_tools.cpp58
-rw-r--r--integration_tests/osrm_test_tools.hpp4
-rw-r--r--iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm2
-rw-r--r--map/active_maps_layout.cpp12
-rw-r--r--map/active_maps_layout.hpp5
-rw-r--r--map/benchmark_engine.cpp7
-rw-r--r--map/benchmark_tool/features_loading.cpp18
-rw-r--r--map/country_tree.cpp2
-rw-r--r--map/country_tree.hpp4
-rw-r--r--map/feature_vec_model.cpp67
-rw-r--r--map/feature_vec_model.hpp60
-rw-r--r--map/framework.cpp240
-rw-r--r--map/framework.hpp18
-rw-r--r--map/map_tests/bookmarks_test.cpp2
-rw-r--r--map/mwm_tests/multithread_mwm_test.cpp2
-rw-r--r--map/mwm_tests/mwm_foreach_test.cpp14
-rw-r--r--map/mwm_tests/mwm_index_test.cpp13
-rw-r--r--map/routing_session.cpp17
-rw-r--r--map/routing_session.hpp36
-rw-r--r--pedestrian_routing_benchmarks/pedestrian_routing_benchmarks.cpp33
-rw-r--r--platform/country_defines.cpp22
-rw-r--r--platform/country_defines.hpp8
-rw-r--r--platform/country_file.cpp2
-rw-r--r--platform/local_country_file.cpp13
-rw-r--r--platform/local_country_file.hpp6
-rw-r--r--platform/local_country_file_utils.cpp31
-rw-r--r--platform/platform.cpp8
-rw-r--r--platform/platform.hpp11
-rw-r--r--platform/platform_android.cpp22
-rw-r--r--platform/platform_ios.mm2
-rw-r--r--platform/platform_tests/local_country_file_tests.cpp214
-rw-r--r--routing/osrm_router.cpp8
-rw-r--r--routing/osrm_router.hpp7
-rw-r--r--routing/road_graph_router.cpp3
-rw-r--r--routing/routing_mapping.cpp52
-rw-r--r--routing/routing_mapping.h29
-rw-r--r--search/search_query.cpp23
-rw-r--r--search/search_tests/house_detector_tests.cpp14
-rw-r--r--search/search_tests/locality_finder_test.cpp7
-rw-r--r--std/algorithm.hpp1
-rw-r--r--storage/country.cpp250
-rw-r--r--storage/country.hpp127
-rw-r--r--storage/map_files_downloader.hpp1
-rw-r--r--storage/queued_country.cpp52
-rw-r--r--storage/queued_country.hpp31
-rw-r--r--storage/storage.cpp1193
-rw-r--r--storage/storage.hpp302
-rw-r--r--storage/storage.pro2
-rw-r--r--storage/storage_defines.hpp2
-rw-r--r--storage/storage_tests/fake_map_files_downloader.hpp1
-rw-r--r--storage/storage_tests/queued_country_tests.cpp106
-rw-r--r--storage/storage_tests/storage_tests.cpp506
-rw-r--r--storage/storage_tests/storage_tests.pro2
66 files changed, 2514 insertions, 1923 deletions
diff --git a/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp b/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp
index 1b6b3c9067..bd6993716b 100644
--- a/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp
+++ b/android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp
@@ -3,9 +3,10 @@
#include "defines.hpp"
-#include "coding/url_encode.hpp"
-#include "coding/reader_streambuf.hpp"
+#include "coding/file_name_utils.hpp"
#include "coding/internal/file_data.hpp"
+#include "coding/reader_streambuf.hpp"
+#include "coding/url_encode.hpp"
#include "platform/platform.hpp"
#include "platform/http_request.hpp"
@@ -212,7 +213,11 @@ extern "C"
storage::Storage const & storage = g_framework->Storage();
for (size_t i = 0; i < curFile.m_urls.size(); ++i)
{
- curFile.m_urls[i] = storage.GetFileDownloadUrl(curFile.m_urls[i], curFile.m_fileName);
+ 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);
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 957e150873..6e9f751f5d 100644
--- a/android/jni/com/mapswithme/maps/Framework.cpp
+++ b/android/jni/com/mapswithme/maps/Framework.cpp
@@ -23,8 +23,11 @@
#include "geometry/angles.hpp"
-#include "platform/measurement_utils.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/platform.hpp"
#include "platform/preferred_languages.hpp"
@@ -45,6 +48,8 @@ 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
{
@@ -553,33 +558,32 @@ namespace android
void Framework::GetMapsWithoutSearch(vector<string> & out) const
{
- ASSERT ( out.empty(), () );
+ ASSERT(out.empty(), ());
::Platform const & pl = GetPlatform();
- vector<string> v;
- m_work.GetMaps(v);
+ vector<LocalCountryFile> localFiles;
+ platform::FindAllLocalMaps(localFiles);
- for (size_t i = 0; i < v.size(); ++i)
+ for (LocalCountryFile const & localFile : localFiles)
{
+ CountryFile const countryFile = localFile.GetCountryFile();
// skip World and WorldCoast
- if (v[i].find(WORLD_FILE_NAME) == string::npos &&
- v[i].find(WORLD_COASTS_FILE_NAME) == string::npos)
+ if (countryFile.GetNameWithoutExt() == WORLD_FILE_NAME ||
+ countryFile.GetNameWithoutExt() == WORLD_COASTS_FILE_NAME)
{
- 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()));
- }
+ 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)
+ {
+ // sdcard can contain dummy _*.mwm files. Suppress these errors.
+ LOG(LWARNING, ("Bad mwm file:", countryFile.GetNameWithoutExt(), "Error:", ex.Msg()));
}
}
}
diff --git a/drape_head/drape_surface.cpp b/drape_head/drape_surface.cpp
index 76df4004da..c1c431ebfa 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 b4771110ba..1ce869d62c 100644
--- a/generator/generator_tests/check_mwms.cpp
+++ b/generator/generator_tests/check_mwms.cpp
@@ -5,6 +5,8 @@
#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"
@@ -12,25 +14,25 @@
UNIT_TEST(CheckMWM_LoadAll)
{
- Platform & pl = GetPlatform();
-
- Platform::FilesList maps;
- pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps);
+ Platform & platform = GetPlatform();
+ vector<platform::LocalCountryFile> localFiles;
+ platform::FindAllLocalMapsInDirectory(platform.WritableDir(), 0 /* version */, localFiles);
model::FeaturesFetcher m;
m.InitClassificator();
- for (string const & s : maps)
+ for (platform::LocalCountryFile const & localFile : localFiles)
{
+ LOG(LINFO, ("Found mwm:", localFile));
try
{
- pair<MwmSet::MwmLock, bool> const p = m.RegisterMap(s);
+ pair<MwmSet::MwmLock, bool> const p = m.RegisterMap(localFile);
TEST(p.first.IsLocked(), ());
TEST(p.second, ());
}
catch (RootException const & ex)
{
- TEST(false, ("Bad mwm file:", s));
+ TEST(false, ("Bad mwm file:", localFile));
}
}
}
diff --git a/generator/routing_generator.cpp b/generator/routing_generator.cpp
index 6e8dedffd6..f74fba8ecd 100644
--- a/generator/routing_generator.cpp
+++ b/generator/routing_generator.cpp
@@ -30,6 +30,9 @@
#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
{
@@ -224,9 +227,13 @@ void BuildRoutingIndex(string const & baseDir, string const & countryName, strin
{
classificator::Load();
- string const mwmFile = baseDir + countryName + DATA_FILE_EXTENSION;
+ 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();
Index index;
- pair<MwmSet::MwmLock, bool> const p = index.Register(mwmFile);
+ pair<MwmSet::MwmLock, bool> const p = index.Register(localFile);
if (!p.second)
{
LOG(LCRITICAL, ("MWM file not found"));
@@ -236,7 +243,7 @@ void BuildRoutingIndex(string const & baseDir, string const & countryName, strin
osrm::NodeDataVectorT nodeData;
gen::OsmID2FeatureID osm2ft;
- if (!LoadIndexes(mwmFile, osrmFile, nodeData, osm2ft))
+ if (!LoadIndexes(localFile.GetPath(TMapOptions::EMap), osrmFile, nodeData, osm2ft))
return;
OsrmFtSegMappingBuilder mapping;
@@ -367,13 +374,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 = mwmFile + ROUTING_FILE_EXTENSION;
+ string const fPath = localFile.GetPath(TMapOptions::ECarRouting);
FilesContainerW routingCont(fPath /*, FileWriter::OP_APPEND*/);
{
// Write version for routing file that is equal to correspondent mwm file.
- FilesContainerR mwmCont(mwmFile);
+ FilesContainerR mwmCont(localFile.GetPath(TMapOptions::EMap));
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 9d8cda8d45..2653e281ad 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(CountryFile const & cnt, TMapOptions opt) const
+ uint64_t GetFileSize(platform::CountryFile const & cnt, TMapOptions opt) const
{
uint64_t sz = 0;
- string const fName = cnt.GetFileWithExt(opt);
+ string const fName = cnt.GetNameWithExt(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)
{
- CountryFile & cnt = c.Value().m_files[i];
+ platform::CountryFile & cnt = c.Value().m_files[i];
++m_processedFiles;
- cnt.AssignSizes(GetFileSize(cnt, TMapOptions::EMap),
- GetFileSize(cnt, TMapOptions::ECarRouting));
+ cnt.SetRemoteSizes(GetFileSize(cnt, TMapOptions::EMap),
+ GetFileSize(cnt, TMapOptions::ECarRouting));
- string const fName = cnt.GetFileWithoutExt() + DATA_FILE_EXTENSION;
+ string const fName = cnt.GetNameWithExt(TMapOptions::EMap);
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 e27814dc74..12d0a02fe7 100644
--- a/indexer/index.cpp
+++ b/indexer/index.cpp
@@ -6,32 +6,27 @@
#include "coding/file_name_utils.hpp"
#include "coding/internal/file_data.hpp"
+using platform::CountryFile;
+using platform::LocalCountryFile;
//////////////////////////////////////////////////////////////////////////////////
// MwmValue implementation
//////////////////////////////////////////////////////////////////////////////////
-MwmValue::MwmValue(string const & name)
- : m_cont(GetPlatform().GetReader(name))
+MwmValue::MwmValue(LocalCountryFile const & localFile)
+ : m_cont(GetPlatform().GetCountryReader(localFile, TMapOptions::EMap)),
+ m_countryFile(localFile.GetCountryFile())
{
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(string const & name, MwmInfo & info) const
+bool Index::GetVersion(LocalCountryFile const & localFile, MwmInfo & info) const
{
- MwmValue value(name);
+ MwmValue value(localFile);
feature::DataHeader const & h = value.GetHeader();
if (!h.IsMWMSuitable())
@@ -47,9 +42,9 @@ bool Index::GetVersion(string const & name, MwmInfo & info) const
return true;
}
-MwmSet::TMwmValueBasePtr Index::CreateValue(string const & name) const
+MwmSet::TMwmValueBasePtr Index::CreateValue(LocalCountryFile const & localFile) const
{
- TMwmValueBasePtr p(new MwmValue(name));
+ TMwmValueBasePtr p(new MwmValue(localFile));
ASSERT(static_cast<MwmValue &>(*p.get()).GetHeader().IsMWMSuitable(), ());
return p;
}
@@ -63,124 +58,23 @@ Index::~Index()
Cleanup();
}
-namespace
+pair<MwmSet::MwmLock, bool> Index::RegisterMap(LocalCountryFile const & 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);
+ pair<MwmSet::MwmLock, bool> result = Register(localFile);
+ if (result.first.IsLocked() && result.second)
+ m_observers.ForEach(&Observer::OnMapRegistered, localFile);
return result;
}
-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::DeregisterMap(CountryFile const & countryFile) { return Deregister(countryFile); }
bool Index::AddObserver(Observer & observer) { return m_observers.Add(observer); }
bool Index::RemoveObserver(Observer const & observer) { return m_observers.Remove(observer); }
-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)
+void Index::OnMwmDeregistered(LocalCountryFile const & localFile)
{
- ClearCache(MwmId(info));
- ReplaceFileWithReady(info->m_fileName);
- info->SetStatus(MwmInfo::STATUS_UP_TO_DATE);
- m_observers.ForEach(&Observer::OnMapUpdated, info->m_fileName);
+ m_observers.ForEach(&Observer::OnMapDeregistered, localFile);
}
//////////////////////////////////////////////////////////////////////////////////
@@ -194,11 +88,11 @@ Index::FeaturesLoaderGuard::FeaturesLoaderGuard(Index const & parent, MwmId id)
{
}
-string Index::FeaturesLoaderGuard::GetFileName() const
+string Index::FeaturesLoaderGuard::GetCountryFileName() const
{
if (!m_lock.IsLocked())
return string();
- return m_lock.GetValue<MwmValue>()->GetFileName();
+ return m_lock.GetValue<MwmValue>()->GetCountryFile().GetNameWithoutExt();
}
bool Index::FeaturesLoaderGuard::IsWorld() const
diff --git a/indexer/index.hpp b/indexer/index.hpp
index c058a0f11b..20d9d75c5d 100644
--- a/indexer/index.hpp
+++ b/indexer/index.hpp
@@ -24,33 +24,25 @@ class MwmValue : public MwmSet::MwmValueBase
public:
FilesContainerR m_cont;
IndexFactory m_factory;
+ platform::CountryFile const m_countryFile;
- explicit MwmValue(string const & name);
+ explicit MwmValue(platform::LocalCountryFile const & localFile);
inline feature::DataHeader const & GetHeader() const { return m_factory.GetHeader(); }
inline version::MwmVersion const & GetMwmVersion() const { return m_factory.GetMwmVersion(); }
- /// @return MWM file name without extension.
- string GetFileName() const;
+ inline platform::CountryFile const & GetCountryFile() const { return m_countryFile; }
};
class Index : public MwmSet
{
protected:
// MwmSet overrides:
- 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;
+ 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;
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
@@ -58,19 +50,14 @@ public:
class Observer
{
public:
- virtual ~Observer() {}
-
- /// Called when a map is registered for a first time.
- virtual void OnMapRegistered(string const & file) {}
+ virtual ~Observer() = default;
- /// Called when an update for a map is downloaded.
- virtual void OnMapUpdateIsReady(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 applied.
- virtual void OnMapUpdated(string const & file) {}
-
- /// Called when a map is deleted.
- virtual void OnMapDeleted(string const & file) {}
+ /// Called when a map is deregistered and can not be used.
+ virtual void OnMapDeregistered(platform::LocalCountryFile const & localFile) {}
};
Index();
@@ -78,37 +65,21 @@ public:
/// Registers a new map.
///
- /// \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.
+ /// \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.
///
- /// \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);
+ /// \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);
bool AddObserver(Observer & observer);
@@ -280,7 +251,7 @@ public:
FeaturesLoaderGuard(Index const & parent, MwmId id);
inline MwmSet::MwmId GetId() const { return m_lock.GetId(); }
- string GetFileName() const;
+ string GetCountryFileName() 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 7efeb27fb6..1ebfe9c068 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(fileName));
+ UNUSED_VALUE(index.Register(platform::LocalCountryFile::MakeForTesting("build_index_test")));
// 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 dfea961b07..1e24aa5365 100644
--- a/indexer/indexer_tests/index_test.cpp
+++ b/indexer/indexer_tests/index_test.cpp
@@ -6,6 +6,8 @@
#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"
@@ -16,6 +18,11 @@
#include "std/bind.hpp"
#include "std/string.hpp"
+using platform::CountryFile;
+using platform::LocalCountryFile;
+
+namespace
+{
void CheckedDeleteFile(string const & file)
{
if (Platform::IsFileExistsByFullPath(file))
@@ -25,57 +32,60 @@ void CheckedDeleteFile(string const & file)
class Observer : public Index::Observer
{
public:
- 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)
+ Observer() : m_numRegisteredCalls(0), m_numDeregisteredCalls(0) {}
+
+ ~Observer() { CheckExpectations(); }
+
+ void ExpectRegisteredMap(platform::LocalCountryFile const & localFile)
{
+ m_expectedRegisteredMaps.push_back(localFile);
}
- // Index::Observer overrides:
- void OnMapRegistered(string const & file) override
+ void ExpectDeregisteredMap(platform::LocalCountryFile const & localFile)
{
- CHECK_EQUAL(m_file, file, ());
- ++m_map_registered_calls;
+ m_expectedDeregisteredMaps.push_back(localFile);
}
- void OnMapUpdateIsReady(string const & file) override
+ void CheckExpectations()
{
- CHECK_EQUAL(m_file, file, ());
- ++m_map_update_is_ready_calls;
+ CHECK_EQUAL(m_numRegisteredCalls, m_expectedRegisteredMaps.size(), ());
+ CHECK_EQUAL(m_numDeregisteredCalls, m_expectedDeregisteredMaps.size(), ());
}
- void OnMapUpdated(string const & file) override
+ // Index::Observer overrides:
+ void OnMapRegistered(platform::LocalCountryFile const & localFile) override
{
- CHECK_EQUAL(m_file, file, ());
- ++m_map_updated_calls;
+ CHECK_LESS(m_numRegisteredCalls, m_expectedRegisteredMaps.size(),
+ ("Unexpected OnMapRegistered() call (", m_numRegisteredCalls, "): ", localFile));
+ CHECK_EQUAL(m_expectedRegisteredMaps[m_numRegisteredCalls], localFile, (m_numRegisteredCalls));
+ ++m_numRegisteredCalls;
}
- void OnMapDeleted(string const & file) override
+ void OnMapDeregistered(platform::LocalCountryFile const & localFile) override
{
- CHECK_EQUAL(m_file, file, ());
- ++m_map_deleted_calls;
+ CHECK_LESS(m_numDeregisteredCalls, m_expectedDeregisteredMaps.size(),
+ ("Unexpected OnMapDeregistered() call (", m_numDeregisteredCalls, "): ", localFile));
+ CHECK_EQUAL(m_expectedDeregisteredMaps[m_numDeregisteredCalls], localFile,
+ (m_numDeregisteredCalls));
+ ++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; }
+ inline size_t MapRegisteredCalls() const { return m_numRegisteredCalls; }
+ inline size_t MapDeregisteredCalls() const { return m_numDeregisteredCalls; }
private:
- 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;
+ size_t m_numRegisteredCalls;
+ size_t m_numDeregisteredCalls;
+
+ vector<LocalCountryFile> m_expectedRegisteredMaps;
+ vector<LocalCountryFile> m_expectedDeregisteredMaps;
};
+} // namespace
UNIT_TEST(Index_Parse)
{
Index index;
- UNUSED_VALUE(index.RegisterMap("minsk-pass" DATA_FILE_EXTENSION));
+ UNUSED_VALUE(index.RegisterMap(platform::LocalCountryFile::MakeForTesting("minsk-pass")));
// Make sure that index is actually parsed.
NoopFunctor fn;
@@ -84,65 +94,68 @@ UNIT_TEST(Index_Parse)
UNIT_TEST(Index_MwmStatusNotifications)
{
- 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;
+ Platform & platform = GetPlatform();
+ string const mapsDir = GetPlatform().WritableDir();
+ CountryFile const countryFile("minsk-pass");
- TEST(my::CopyFileX(sourceMapPath, testMapPath), ());
- MY_SCOPE_GUARD(testMapGuard, bind(&CheckedDeleteFile, testMapPath));
+ // 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 */);
Index index;
- Observer observer(testMapName);
+ Observer observer;
index.AddObserver(observer);
- TEST_EQUAL(0, observer.map_registered_calls(), ());
+ TEST_EQUAL(0, observer.MapRegisteredCalls(), ());
+
+ MwmSet::MwmId localFileV1Id;
// Checks that observers are triggered after map registration.
{
- pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(testMapName);
+ observer.ExpectRegisteredMap(localFileV1);
+ pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(localFileV1);
TEST(p.first.IsLocked(), ());
TEST(p.second, ());
- TEST_EQUAL(1, observer.map_registered_calls(), ());
+ observer.CheckExpectations();
+ localFileV1Id = p.first.GetId();
}
- // Checks that map can't registered twice and observers aren't
- // triggered.
+ // Checks that map can't registered twice.
{
- pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(testMapName);
+ pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(localFileV1);
TEST(p.first.IsLocked(), ());
TEST(!p.second, ());
- TEST_EQUAL(1, observer.map_registered_calls(), ());
+ observer.CheckExpectations();
+ TEST_EQUAL(localFileV1Id, p.first.GetId(), ());
}
- TEST(my::CopyFileX(testMapPath, testMapUpdatePath), ());
- MY_SCOPE_GUARD(testMapUpdateGuard, bind(&CheckedDeleteFile, testMapUpdatePath));
-
- // Checks that observers are notified when map is deleted.
+ // Checks that observers are notified when map is updated.
+ MwmSet::MwmId localFileV2Id;
{
- 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);
+ observer.ExpectRegisteredMap(localFileV2);
+ observer.ExpectDeregisteredMap(localFileV1);
+ pair<MwmSet::MwmLock, bool> const p = index.RegisterMap(localFileV2);
TEST(p.first.IsLocked(), ());
- TEST_EQUAL(Index::UPDATE_STATUS_OK, p.second, ());
- TEST_EQUAL(1, observer.map_update_is_ready_calls(), ());
- TEST_EQUAL(1, observer.map_updated_calls(), ());
+ TEST(p.second, ());
+ observer.CheckExpectations();
+ localFileV2Id = p.first.GetId();
+ TEST_NOT_EQUAL(localFileV1Id, localFileV2Id, ());
}
- // Tries to delete map in presence of active lock. Map should be
- // marked "to be removed" but can't be deleted.
+ // 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.
{
- MwmSet::MwmLock const lock = index.GetMwmLockByFileName(testMapName);
+ MwmSet::MwmLock const lock = index.GetMwmLockByCountryFile(countryFile);
TEST(lock.IsLocked(), ());
- TEST(!index.DeleteMap(testMapName), ());
- TEST_EQUAL(0, observer.map_deleted_calls(), ());
- }
-
- // Checks that observers are notified when all locks are destroyed.
- TEST_EQUAL(1, observer.map_deleted_calls(), ());
+ TEST(!index.DeregisterMap(countryFile), ());
+ observer.CheckExpectations();
+ observer.ExpectDeregisteredMap(localFileV2);
+ }
+ observer.CheckExpectations();
index.RemoveObserver(observer);
}
diff --git a/indexer/indexer_tests/mwm_set_test.cpp b/indexer/indexer_tests/mwm_set_test.cpp
index 27fd148f6b..30b9adebe5 100644
--- a/indexer/indexer_tests/mwm_set_test.cpp
+++ b/indexer/indexer_tests/mwm_set_test.cpp
@@ -7,6 +7,11 @@
#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
@@ -16,16 +21,17 @@ class MwmValue : public MwmSet::MwmValueBase
class TestMwmSet : public MwmSet
{
protected:
- bool GetVersion(string const & path, MwmInfo & info) const override
+ // MwmSet overrides:
+ bool GetVersion(LocalCountryFile const & localFile, MwmInfo & info) const override
{
- int const n = path[0] - '0';
+ int const n = localFile.GetCountryFile().GetNameWithoutExt()[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(string const &) const override
+ TMwmValueBasePtr CreateValue(LocalCountryFile const &) const override
{
return TMwmValueBasePtr(new MwmValue());
}
@@ -34,23 +40,21 @@ public:
~TestMwmSet() { Cleanup(); }
};
-void GetMwmsInfo(MwmSet const & mwmSet,
- unordered_map<MwmSet::TMwmFileName, shared_ptr<MwmInfo>> & mwmsInfo)
+void GetMwmsInfo(MwmSet const & mwmSet, TMwmsInfo & mwmsInfo)
{
vector<shared_ptr<MwmInfo>> mwmsInfoList;
mwmSet.GetMwmsInfo(mwmsInfoList);
mwmsInfo.clear();
for (shared_ptr<MwmInfo> const & info : mwmsInfoList)
- mwmsInfo[info->GetFileName()] = info;
+ mwmsInfo[info->GetCountryName()] = info;
}
-void TestFilesPresence(unordered_map<MwmSet::TMwmFileName, shared_ptr<MwmInfo>> const & mwmsInfo,
- initializer_list<MwmSet::TMwmFileName> const & expectedNames)
+void TestFilesPresence(TMwmsInfo const & mwmsInfo, initializer_list<string> const & expectedNames)
{
TEST_EQUAL(expectedNames.size(), mwmsInfo.size(), ());
- for (MwmSet::TMwmFileName const & fileName : expectedNames)
- TEST_EQUAL(1, mwmsInfo.count(fileName), (fileName));
+ for (string const & countryFileName : expectedNames)
+ TEST_EQUAL(1, mwmsInfo.count(countryFileName), (countryFileName));
}
} // namespace
@@ -58,12 +62,12 @@ void TestFilesPresence(unordered_map<MwmSet::TMwmFileName, shared_ptr<MwmInfo>>
UNIT_TEST(MwmSetSmokeTest)
{
TestMwmSet mwmSet;
- unordered_map<MwmSet::TMwmFileName, shared_ptr<MwmInfo>> mwmsInfo;
+ TMwmsInfo mwmsInfo;
- UNUSED_VALUE(mwmSet.Register("0"));
- UNUSED_VALUE(mwmSet.Register("1"));
- UNUSED_VALUE(mwmSet.Register("2"));
- mwmSet.Deregister("1");
+ 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"));
GetMwmsInfo(mwmSet, mwmsInfo);
TestFilesPresence(mwmsInfo, {"0", "2"});
@@ -72,13 +76,13 @@ UNIT_TEST(MwmSetSmokeTest)
TEST_EQUAL(mwmsInfo["0"]->m_maxScale, 0, ());
TEST(mwmsInfo["2"]->IsUpToDate(), ());
{
- MwmSet::MwmLock const lock0 = mwmSet.GetMwmLockByFileName("0");
- MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByFileName("1");
+ MwmSet::MwmLock const lock0 = mwmSet.GetMwmLockByCountryFile(CountryFile("0"));
+ MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByCountryFile(CountryFile("1"));
TEST(lock0.IsLocked(), ());
TEST(!lock1.IsLocked(), ());
}
- UNUSED_VALUE(mwmSet.Register("3"));
+ UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("3")));
GetMwmsInfo(mwmSet, mwmsInfo);
TestFilesPresence(mwmsInfo, {"0", "2", "3"});
@@ -91,10 +95,10 @@ UNIT_TEST(MwmSetSmokeTest)
TEST_EQUAL(mwmsInfo["3"]->m_maxScale, 3, ());
{
- MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByFileName("1");
+ MwmSet::MwmLock const lock1 = mwmSet.GetMwmLockByCountryFile(CountryFile("1"));
TEST(!lock1.IsLocked(), ());
- mwmSet.Deregister("3");
- UNUSED_VALUE(mwmSet.Register("4"));
+ mwmSet.Deregister(CountryFile("3"));
+ UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("4")));
}
GetMwmsInfo(mwmSet, mwmsInfo);
@@ -107,7 +111,7 @@ UNIT_TEST(MwmSetSmokeTest)
TEST(mwmsInfo["4"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["4"]->m_maxScale, 4, ());
- UNUSED_VALUE(mwmSet.Register("5"));
+ UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("5")));
GetMwmsInfo(mwmSet, mwmsInfo);
TestFilesPresence(mwmsInfo, {"0", "2", "4", "5"});
@@ -126,17 +130,17 @@ UNIT_TEST(MwmSetSmokeTest)
UNIT_TEST(MwmSetIdTest)
{
TestMwmSet mwmSet;
- TEST(mwmSet.Register("3").second, ());
+ TEST(mwmSet.Register(LocalCountryFile::MakeForTesting("3")).second, ());
- MwmSet::MwmId const id0 = mwmSet.GetMwmLockByFileName("3").GetId();
- MwmSet::MwmId const id1 = mwmSet.GetMwmLockByFileName("3").GetId();
+ MwmSet::MwmId const id0 = mwmSet.GetMwmLockByCountryFile(CountryFile("3")).GetId();
+ MwmSet::MwmId const id1 = mwmSet.GetMwmLockByCountryFile(CountryFile("3")).GetId();
TEST(id0.IsAlive(), ());
TEST(id1.IsAlive(), ());
TEST_EQUAL(id0.GetInfo().get(), id1.GetInfo().get(), ());
- TEST_EQUAL(MwmInfo::STATUS_UP_TO_DATE, id0.GetInfo()->GetStatus(), ());
+ TEST_EQUAL(MwmInfo::STATUS_REGISTERED, id0.GetInfo()->GetStatus(), ());
- TEST(mwmSet.Deregister("3"), ());
+ TEST(mwmSet.Deregister(CountryFile("3")), ());
// Test that both id's are sour now.
TEST(!id0.IsAlive(), ());
@@ -151,14 +155,15 @@ UNIT_TEST(MwmSetLockAndIdTest)
MwmSet::MwmId id;
{
- pair<MwmSet::MwmLock, bool> const lockFlag = mwmSet.Register("4");
+ pair<MwmSet::MwmLock, bool> const lockFlag =
+ mwmSet.Register(LocalCountryFile::MakeForTesting("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_UP_TO_DATE, lock.GetInfo()->GetStatus(), ());
+ TEST_EQUAL(MwmInfo::STATUS_REGISTERED, lock.GetInfo()->GetStatus(), ());
- TEST(!mwmSet.Deregister("4"), ()); // It's not possible to remove mwm 4 right now.
+ TEST(!mwmSet.Deregister(CountryFile("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();
@@ -172,7 +177,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.GetMwmLockByFileName("4");
+ MwmSet::MwmLock lock = mwmSet.GetMwmLockByCountryFile(CountryFile("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 c9005078ce..d6961ebdd0 100644
--- a/indexer/mwm_set.cpp
+++ b/indexer/mwm_set.cpp
@@ -9,6 +9,9 @@
#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
@@ -74,57 +77,64 @@ 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::GetMwmIdByFileNameImpl(TMwmFileName const & name) const
+MwmSet::MwmId MwmSet::GetMwmIdByCountryFileImpl(CountryFile const & countryFile) const
{
+ string const name = countryFile.GetNameWithoutExt();
ASSERT(!name.empty(), ());
auto const it = m_info.find(name);
- if (it == m_info.cend())
+ if (it == m_info.cend() || it->second.empty())
return MwmId();
- return MwmId(it->second);
+ return MwmId(it->second.back());
}
-pair<MwmSet::MwmLock, bool> MwmSet::Register(TMwmFileName const & fileName)
+pair<MwmSet::MwmLock, bool> MwmSet::Register(LocalCountryFile const & localFile)
{
lock_guard<mutex> lock(m_lock);
- MwmId const id = GetMwmIdByFileNameImpl(fileName);
+ CountryFile const & countryFile = localFile.GetCountryFile();
+ MwmId const id = GetMwmIdByCountryFileImpl(countryFile);
if (!id.IsAlive())
- return RegisterImpl(fileName);
+ return RegisterImpl(localFile);
+
shared_ptr<MwmInfo> info = id.GetInfo();
- 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);
+
+ // 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);
}
-pair<MwmSet::MwmLock, bool> MwmSet::RegisterImpl(TMwmFileName const & fileName)
+pair<MwmSet::MwmLock, bool> MwmSet::RegisterImpl(LocalCountryFile const & localFile)
{
shared_ptr<MwmInfo> info(new MwmInfo());
// This function can throw an exception for a bad mwm file.
- if (!GetVersion(fileName, *info))
+ if (!GetVersion(localFile, *info))
return make_pair(MwmLock(), false);
- info->SetStatus(MwmInfo::STATUS_UP_TO_DATE);
- info->m_fileName = fileName;
- m_info[fileName] = info;
+ info->SetStatus(MwmInfo::STATUS_REGISTERED);
+ info->m_file = localFile;
+ string const name = localFile.GetCountryFile().GetNameWithoutExt();
+ vector<shared_ptr<MwmInfo>> & infos = m_info[name];
+ infos.push_back(info);
return make_pair(GetLock(MwmId(info)), true);
}
@@ -133,26 +143,28 @@ 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);
- m_info.erase(info->m_fileName);
- OnMwmDeleted(info);
+ vector<shared_ptr<MwmInfo>> & infos = m_info[info->GetCountryName()];
+ infos.erase(remove(infos.begin(), infos.end(), info), infos.end());
+ OnMwmDeregistered(info->GetLocalFile());
return true;
}
info->SetStatus(MwmInfo::STATUS_MARKED_TO_DEREGISTER);
return false;
}
-bool MwmSet::Deregister(TMwmFileName const & fileName)
+bool MwmSet::Deregister(CountryFile const & countryFile)
{
lock_guard<mutex> lock(m_lock);
- return DeregisterImpl(fileName);
+ return DeregisterImpl(countryFile);
}
-bool MwmSet::DeregisterImpl(TMwmFileName const & fileName)
+bool MwmSet::DeregisterImpl(CountryFile const & countryFile)
{
- MwmId const id = GetMwmIdByFileNameImpl(fileName);
+ MwmId const id = GetMwmIdByCountryFileImpl(countryFile);
if (!id.IsAlive())
return false;
bool const deregistered = DeregisterImpl(id);
@@ -164,21 +176,24 @@ void MwmSet::DeregisterAll()
{
lock_guard<mutex> lock(m_lock);
- for (auto it = m_info.begin(); it != m_info.end();)
+ for (auto const & p : m_info)
{
- auto cur = it++;
- DeregisterImpl(MwmId(cur->second));
+ // 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));
}
// Do not call ClearCache - it's under mutex lock.
ClearCacheImpl(m_cache.begin(), m_cache.end());
}
-bool MwmSet::IsLoaded(TMwmFileName const & fileName) const
+bool MwmSet::IsLoaded(CountryFile const & countryFile) const
{
lock_guard<mutex> lock(m_lock);
- MwmId const id = GetMwmIdByFileNameImpl(fileName + DATA_FILE_EXTENSION);
+ MwmId const id = GetMwmIdByCountryFileImpl(countryFile);
return id.IsAlive() && id.GetInfo()->IsRegistered();
}
@@ -188,7 +203,10 @@ void MwmSet::GetMwmsInfo(vector<shared_ptr<MwmInfo>> & info) const
info.clear();
info.reserve(m_info.size());
for (auto const & p : m_info)
- info.push_back(p.second);
+ {
+ if (!p.second.empty())
+ info.push_back(p.second.back());
+ }
}
MwmSet::TMwmValueBasePtr MwmSet::LockValue(MwmId const & id)
@@ -216,7 +234,7 @@ MwmSet::TMwmValueBasePtr MwmSet::LockValueImpl(MwmId const & id)
return result;
}
}
- return CreateValue(info->m_fileName);
+ return CreateValue(info->GetLocalFile());
}
void MwmSet::UnlockValue(MwmId const & id, TMwmValueBasePtr p)
@@ -233,22 +251,10 @@ void MwmSet::UnlockValueImpl(MwmId const & id, TMwmValueBasePtr p)
return;
shared_ptr<MwmInfo> const & info = id.GetInfo();
- CHECK_GREATER(info->m_lockCount, 0, ());
+ ASSERT_GREATER(info->m_lockCount, 0, ());
--info->m_lockCount;
- 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->m_lockCount == 0 && info->GetStatus() == MwmInfo::STATUS_MARKED_TO_DEREGISTER)
+ VERIFY(DeregisterImpl(id), ());
if (info->IsUpToDate())
{
@@ -267,20 +273,20 @@ void MwmSet::ClearCache()
ClearCacheImpl(m_cache.begin(), m_cache.end());
}
-MwmSet::MwmId MwmSet::GetMwmIdByFileName(TMwmFileName const & fileName) const
+MwmSet::MwmId MwmSet::GetMwmIdByCountryFile(CountryFile const & countryFile) const
{
lock_guard<mutex> lock(m_lock);
- MwmId const id = GetMwmIdByFileNameImpl(fileName);
- ASSERT(id.IsAlive(), ("Can't get an mwm's (", fileName, ") identifier."));
+ MwmId const id = GetMwmIdByCountryFileImpl(countryFile);
+ ASSERT(id.IsAlive(), ("Can't get an mwm's (", countryFile.GetNameWithoutExt(), ") identifier."));
return id;
}
-MwmSet::MwmLock MwmSet::GetMwmLockByFileName(TMwmFileName const & fileName)
+MwmSet::MwmLock MwmSet::GetMwmLockByCountryFile(CountryFile const & countryFile)
{
lock_guard<mutex> lock(m_lock);
- MwmId const id = GetMwmIdByFileNameImpl(fileName);
+ MwmId const id = GetMwmIdByCountryFileImpl(countryFile);
TMwmValueBasePtr value(nullptr);
if (id.IsAlive())
value = LockValueImpl(id);
diff --git a/indexer/mwm_set.hpp b/indexer/mwm_set.hpp
index 25682c16b0..dfc225f4c4 100644
--- a/indexer/mwm_set.hpp
+++ b/indexer/mwm_set.hpp
@@ -2,6 +2,9 @@
#include "indexer/mwm_version.hpp"
+#include "platform/country_file.hpp"
+#include "platform/local_country_file.hpp"
+
#include "geometry/rect2d.hpp"
#include "base/macros.hpp"
@@ -31,10 +34,9 @@ public:
enum Status
{
- 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
+ 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.
};
MwmInfo();
@@ -46,31 +48,32 @@ public:
inline Status GetStatus() const { return m_status; }
+ inline bool IsUpToDate() const { return IsRegistered(); }
+
inline bool IsRegistered() const
{
- return m_status == STATUS_UP_TO_DATE || m_status == STATUS_PENDING_UPDATE;
+ return m_status == STATUS_REGISTERED;
}
- inline bool IsUpToDate() const { return m_status == STATUS_UP_TO_DATE; }
+ inline platform::LocalCountryFile const & GetLocalFile() const { return m_file; }
+
+ inline string GetCountryName() const { return m_file.GetCountryFile().GetNameWithoutExt(); }
- inline string const & GetFileName() const { return m_fileName; }
+ inline int64_t GetVersion() const { return m_file.GetVersion(); }
MwmTypeT GetType() const;
private:
inline void SetStatus(Status status) { m_status = status; }
- string m_fileName; ///< Path to the mwm file.
- Status m_status; ///< Current country status.
- uint8_t m_lockCount; ///< Number of locks.
+ platform::LocalCountryFile m_file; ///< 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:
@@ -94,9 +97,9 @@ public:
friend ostream & operator<<(ostream & os, MwmId const & id)
{
if (id.m_info.get())
- os << "MwmId[" << id.m_info->GetFileName() << "]";
+ os << "MwmId [" << id.m_info->GetCountryName() << "]";
else
- os << "MwmId[invalid]";
+ os << "MwmId [invalid]";
return os;
}
@@ -152,41 +155,43 @@ public:
/// Registers a new map.
///
- /// \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:
+ /// \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.
///
- /// * 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
- //@{
+ /// *NOTE* When a new version for the same country is registered,
+ /// all previous versions will be automatically deregistered.
protected:
- WARN_UNUSED_RESULT pair<MwmLock, bool> RegisterImpl(TMwmFileName const & fileName);
+ WARN_UNUSED_RESULT pair<MwmLock, bool> RegisterImpl(platform::LocalCountryFile const & localFile);
public:
- WARN_UNUSED_RESULT pair<MwmLock, bool> Register(TMwmFileName const & fileName);
+ WARN_UNUSED_RESULT pair<MwmLock, bool> Register(platform::LocalCountryFile const & localFile);
//@}
/// @name Remove mwm.
//@{
protected:
- /// Deregisters a map from the set when it's possible. Note that an
- /// underlying file is not deleted.
+ /// Deregisters a map from internal records.
///
- /// @return true when the map was deregistered.
+ /// \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 DeregisterImpl(MwmId const & id);
- bool DeregisterImpl(TMwmFileName const & ofileName);
+ bool DeregisterImpl(platform::CountryFile const & countryFile);
//@}
public:
- bool Deregister(TMwmFileName const & fileName);
+ bool Deregister(platform::CountryFile const & countryFile);
void DeregisterAll();
//@}
- /// @param[in] file File name without extension.
- bool IsLoaded(TMwmFileName const & fileName) const;
+ /// Returns true when country is registered and can be used.
+ bool IsLoaded(platform::CountryFile const & countryFile) const;
/// Get ids of all mwms. Some of them may be with not active status.
/// In that case, LockValue returns NULL.
@@ -194,14 +199,14 @@ public:
void ClearCache();
- MwmId GetMwmIdByFileName(TMwmFileName const & fileName) const;
+ MwmId GetMwmIdByCountryFile(platform::CountryFile const & countryFile) const;
- MwmLock GetMwmLockByFileName(TMwmFileName const & fileName);
+ MwmLock GetMwmLockByCountryFile(platform::CountryFile const & countryFile);
protected:
/// @return True when file format version was successfully read to MwmInfo.
- virtual bool GetVersion(TMwmFileName const & fileName, MwmInfo & info) const = 0;
- virtual TMwmValueBasePtr CreateValue(string const & name) const = 0;
+ virtual bool GetVersion(platform::LocalCountryFile const & localFile, MwmInfo & info) const = 0;
+ virtual TMwmValueBasePtr CreateValue(platform::LocalCountryFile const & localFile) const = 0;
void Cleanup();
@@ -226,7 +231,7 @@ protected:
/// Find mwm with a given name.
/// @precondition This function is always called under mutex m_lock.
- MwmId GetMwmIdByFileNameImpl(TMwmFileName const & fileName) const;
+ MwmId GetMwmIdByCountryFileImpl(platform::CountryFile const & countryFile) const;
/// @precondition This function is always called under mutex m_lock.
WARN_UNUSED_RESULT inline MwmLock GetLock(MwmId const & id)
@@ -236,12 +241,9 @@ protected:
// This method is called under m_lock when mwm is removed from a
// registry.
- 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) {}
+ virtual void OnMwmDeregistered(platform::LocalCountryFile const & localFile) {}
- TMwmInfoTable m_info;
+ map<string, vector<shared_ptr<MwmInfo>>> m_info;
mutable mutex m_lock;
};
diff --git a/integration_tests/osrm_test_tools.cpp b/integration_tests/osrm_test_tools.cpp
index 90f9dbeaa9..4bf6cd94b8 100644
--- a/integration_tests/osrm_test_tools.cpp
+++ b/integration_tests/osrm_test_tools.cpp
@@ -11,6 +11,8 @@
#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"
@@ -20,6 +22,7 @@
using namespace routing;
+using platform::LocalCountryFile;
namespace
{
@@ -34,19 +37,19 @@ namespace
namespace integration
{
- shared_ptr<model::FeaturesFetcher> CreateFeaturesFetcher(vector<string> const & mapNames)
+ shared_ptr<model::FeaturesFetcher> CreateFeaturesFetcher(vector<LocalCountryFile> const & localFiles)
{
size_t const maxOpenFileNumber = 1024;
ChangeMaxNumberOfOpenFiles(maxOpenFileNumber);
shared_ptr<model::FeaturesFetcher> featuresFetcher(new model::FeaturesFetcher);
featuresFetcher->InitClassificator();
- for (auto const mapName : mapNames)
+ for (LocalCountryFile const & localFile : localFiles)
{
- pair<MwmSet::MwmLock, bool> result = featuresFetcher->RegisterMap(mapName);
+ pair<MwmSet::MwmLock, bool> result = featuresFetcher->RegisterMap(localFile);
if (!result.second)
{
- ASSERT(false, ());
+ ASSERT(false, ("Can't register", localFile));
return nullptr;
}
}
@@ -82,21 +85,27 @@ namespace integration
ASSERT(featuresFetcher, ());
ASSERT(searchEngine, ());
- shared_ptr<OsrmRouter> osrmRouter(new OsrmRouter(&featuresFetcher->GetIndex(),
- [searchEngine](m2::PointD const & pt)
- {
- return searchEngine->GetCountryFile(pt);
- }));
+ 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));
+ }));
return osrmRouter;
}
class OsrmRouterComponents
{
public:
- OsrmRouterComponents(vector<string> const & mapNames)
- : m_featuresFetcher(CreateFeaturesFetcher(mapNames)),
- m_searchEngine(CreateSearchEngine(m_featuresFetcher)),
- m_osrmRouter(CreateOsrmRouter(m_featuresFetcher, m_searchEngine)) {}
+ OsrmRouterComponents(vector<LocalCountryFile> const & localFiles)
+ : m_featuresFetcher(CreateFeaturesFetcher(localFiles)),
+ 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(); }
@@ -106,28 +115,17 @@ namespace integration
shared_ptr<OsrmRouter> m_osrmRouter;
};
- 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)
+ shared_ptr<OsrmRouterComponents> LoadMaps(vector<LocalCountryFile> const & localFiles)
{
- return shared_ptr<OsrmRouterComponents>(new OsrmRouterComponents(mapNames));
+ return shared_ptr<OsrmRouterComponents>(new OsrmRouterComponents(localFiles));
}
shared_ptr<OsrmRouterComponents> LoadAllMaps()
{
- vector<string> maps;
- GetMapNames(maps);
- ASSERT(!maps.empty(), ());
- return LoadMaps(maps);
+ vector<LocalCountryFile> localFiles;
+ platform::FindAllLocalMaps(localFiles);
+ ASSERT(!localFiles.empty(), ());
+ return LoadMaps(localFiles);
}
OsrmRouterComponents & GetAllMaps()
diff --git a/integration_tests/osrm_test_tools.hpp b/integration_tests/osrm_test_tools.hpp
index 8bc5608e7a..b6d23146d7 100644
--- a/integration_tests/osrm_test_tools.hpp
+++ b/integration_tests/osrm_test_tools.hpp
@@ -8,6 +8,8 @@
#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.
@@ -46,7 +48,7 @@ namespace integration
OsrmRouterComponents & routerComponents);
OsrmRouterComponents & GetAllMaps();
- shared_ptr<OsrmRouterComponents> LoadMaps(vector<string> const & mapNames);
+ shared_ptr<OsrmRouterComponents> LoadMaps(vector<platform::LocalCountryFile> const & localFiles);
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 567183be8d..c1ff8c6a9c 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 \ No newline at end of file
+@end
diff --git a/map/active_maps_layout.cpp b/map/active_maps_layout.cpp
index 8dc200ded3..090cef36b5 100644
--- a/map/active_maps_layout.cpp
+++ b/map/active_maps_layout.cpp
@@ -36,14 +36,14 @@ ActiveMapsLayout::~ActiveMapsLayout()
#endif
}
-void ActiveMapsLayout::Init(vector<string> const & maps)
+void ActiveMapsLayout::Init(vector<platform::CountryFile> const & files)
{
Clear();
Storage & storage = GetStorage();
- for (auto const & file : maps)
+ for (auto const & file : files)
{
- vector<TIndex> arr = storage.FindAllIndexesByFile(Storage::MapWithoutExt(file));
+ vector<TIndex> arr = storage.FindAllIndexesByFile(file.GetNameWithoutExt());
if (!arr.empty())
{
TStatus status;
@@ -53,7 +53,9 @@ void ActiveMapsLayout::Init(vector<string> const & maps)
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)
@@ -237,7 +239,7 @@ LocalAndRemoteSizeT const ActiveMapsLayout::GetRemoteCountrySizes(TGroup const &
LocalAndRemoteSizeT const ActiveMapsLayout::GetRemoteCountrySizes(TIndex const & index) const
{
- CountryFile const & c = GetStorage().CountryByIndex(index).GetFile();
+ platform::CountryFile const & c = GetStorage().CountryByIndex(index).GetFile();
size_t const mapSize = c.GetRemoteSize(TMapOptions::EMap);
return { mapSize, c.GetRemoteSize(TMapOptions::ECarRouting) };
}
@@ -265,7 +267,7 @@ void ActiveMapsLayout::DownloadMap(TIndex const & index, TMapOptions const & opt
else
{
Storage const & s = GetStorage();
- vector<TIndex> arr = s.FindAllIndexesByFile(s.CountryFileNameWithoutExt(index));
+ vector<TIndex> arr = s.FindAllIndexesByFile(s.GetCountryFile(index).GetNameWithoutExt());
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 27c1e101e4..331d17296b 100644
--- a/map/active_maps_layout.hpp
+++ b/map/active_maps_layout.hpp
@@ -1,9 +1,10 @@
#pragma once
-#include "storage/storage_defines.hpp"
#include "storage/index.hpp"
+#include "storage/storage_defines.hpp"
#include "platform/country_defines.hpp"
+#include "platform/country_file.hpp"
#include "base/buffer_vector.hpp"
@@ -95,7 +96,7 @@ private:
Storage const & GetStorage() const;
Storage & GetStorage();
- void Init(vector<string> const & maps);
+ void Init(vector<platform::CountryFile> const & files);
void Clear();
void ShowMap(TIndex const & index);
diff --git a/map/benchmark_engine.cpp b/map/benchmark_engine.cpp
index 3c99a0b9f9..208cd1bb94 100644
--- a/map/benchmark_engine.cpp
+++ b/map/benchmark_engine.cpp
@@ -133,8 +133,11 @@ void BenchmarkEngine::PrepareMaps()
// add only maps needed for benchmarks
MapsCollector collector;
ForEachBenchmarkRecord(collector);
- for_each(collector.m_maps.begin(), collector.m_maps.end(),
- bind(&Framework::RegisterMap, m_framework, _1));
+ for (string const & map : collector.m_maps)
+ {
+ LOG(LINFO, ("Looking for:", map));
+ m_framework->RegisterMap(platform::LocalCountryFile::MakeForTesting(map));
+ }
}
BenchmarkEngine::BenchmarkEngine(Framework * fw)
diff --git a/map/benchmark_tool/features_loading.cpp b/map/benchmark_tool/features_loading.cpp
index c9fd84ab7d..a316188916 100644
--- a/map/benchmark_tool/features_loading.cpp
+++ b/map/benchmark_tool/features_loading.cpp
@@ -9,6 +9,8 @@
#include "platform/platform.hpp"
+#include "coding/file_name_utils.hpp"
+
#include "base/macros.hpp"
#include "base/timer.hpp"
@@ -97,8 +99,20 @@ 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().GetReader(file), header);
+ LoadMapHeader(GetPlatform().GetCountryReader(localFile, TMapOptions::EMap), header);
pair<int, int> const r = header.GetScaleRange();
if (r.first > scaleR.first)
@@ -110,7 +124,7 @@ void RunFeaturesLoadingBenchmark(string const & file, pair<int, int> scaleR, All
return;
model::FeaturesFetcher src;
- UNUSED_VALUE(src.RegisterMap(file));
+ UNUSED_VALUE(src.RegisterMap(platform::LocalCountryFile::MakeForTesting(countryFileName)));
RunBenchmark(src, header.GetBounds(), scaleR, res);
}
diff --git a/map/country_tree.cpp b/map/country_tree.cpp
index e0c53bccd2..4d62070703 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<string> const & maps)
+void CountryTree::Init(vector<platform::CountryFile> const & maps)
{
ASSERT(IsValid(), ());
m_layout->Init(maps);
diff --git a/map/country_tree.hpp b/map/country_tree.hpp
index ab8e88838a..2a28dce7a3 100644
--- a/map/country_tree.hpp
+++ b/map/country_tree.hpp
@@ -5,6 +5,8 @@
#include "storage/index.hpp"
#include "storage/storage_defines.hpp"
+#include "platform/country_file.hpp"
+
#include "base/buffer_vector.hpp"
#include "std/string.hpp"
@@ -36,7 +38,7 @@ public:
CountryTree & operator=(CountryTree const & other);
/// @param[in] Sorted vector of current .mwm files.
- void Init(vector<string> const & maps);
+ void Init(vector<platform::CountryFile> const & maps);
void Clear();
ActiveMapsLayout & GetActiveMapLayout();
diff --git a/map/feature_vec_model.cpp b/map/feature_vec_model.cpp
index ec7b701f25..ca5f1f4ba0 100644
--- a/map/feature_vec_model.cpp
+++ b/map/feature_vec_model.cpp
@@ -13,9 +13,20 @@
#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.
@@ -33,71 +44,47 @@ void FeaturesFetcher::InitClassificator()
}
}
-pair<MwmSet::MwmLock, bool> FeaturesFetcher::RegisterMap(string const & file)
+pair<MwmSet::MwmLock, bool> FeaturesFetcher::RegisterMap(LocalCountryFile const & localFile)
{
+ string const countryFileName = localFile.GetCountryFile().GetNameWithoutExt();
try
{
- pair<MwmSet::MwmLock, bool> p = m_multiIndex.RegisterMap(file);
- if (!p.second)
+ pair<MwmSet::MwmLock, bool> result = m_multiIndex.RegisterMap(localFile);
+ if (!result.second)
{
- LOG(LWARNING,
- ("Can't add map", file, "Probably it's already added or has newer data version."));
- return p;
+ LOG(LWARNING, ("Can't add map", countryFileName,
+ "Probably it's already added or has newer data version."));
+ return result;
}
- MwmSet::MwmLock & lock = p.first;
+ MwmSet::MwmLock & lock = result.first;
ASSERT(lock.IsLocked(), ("Mwm lock invariant violation."));
m_rect.Add(lock.GetInfo()->m_limitRect);
- return p;
+ return result;
}
catch (RootException const & e)
{
- LOG(LERROR, ("IO error while adding ", file, " map. ", e.what()));
+ LOG(LERROR, ("IO error while adding ", countryFileName, " map. ", e.what()));
return make_pair(MwmSet::MwmLock(), false);
}
}
-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)
+bool FeaturesFetcher::DeregisterMap(CountryFile const & countryFile)
{
- return m_multiIndex.UpdateMap(file);
+ return m_multiIndex.Deregister(countryFile);
}
-//void FeaturesFetcher::Clean()
-//{
-// m_rect.MakeEmpty();
-// // TODO: m_multiIndex.Clear(); - is it needed?
-//}
+void FeaturesFetcher::DeregisterAllMaps() { m_multiIndex.DeregisterAll(); }
void FeaturesFetcher::ClearCaches()
{
m_multiIndex.ClearCache();
}
-/*
-bool FeaturesFetcher::IsLoaded(m2::PointD const & pt) const
+void FeaturesFetcher::OnMapDeregistered(platform::LocalCountryFile const & 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;
+ if (m_onMapDeregistered)
+ m_onMapDeregistered(localFile);
}
-*/
m2::RectD FeaturesFetcher::GetWorldRect() const
{
diff --git a/map/feature_vec_model.hpp b/map/feature_vec_model.hpp
index b671ba0721..9698d5a745 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
+class FeaturesFetcher : public Index::Observer
{
public:
#ifdef USE_BUFFER_READER
@@ -24,58 +24,56 @@ namespace model
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. 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);
+ /// \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);
/// Deregisters a map denoted by file from internal records.
- void DeregisterMap(string const & file);
+ bool DeregisterMap(platform::CountryFile const & countryFile);
/// 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 & fName) const
+ inline bool IsLoaded(string const & countryFileName) const
{
- return m_multiIndex.IsLoaded(fName);
+ return m_multiIndex.IsLoaded(platform::CountryFile(countryFileName));
}
+ // 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 9265215902..e4083f8004 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -44,10 +44,11 @@
#include "gui/controller.hpp"
+#include "platform/local_country_file_utils.hpp"
#include "platform/measurement_utils.hpp"
-#include "platform/settings.hpp"
-#include "platform/preferred_languages.hpp"
#include "platform/platform.hpp"
+#include "platform/preferred_languages.hpp"
+#include "platform/settings.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/zip_reader.hpp"
@@ -81,6 +82,8 @@ using namespace storage;
using namespace routing;
using namespace location;
+using platform::CountryFile;
+using platform::LocalCountryFile;
#ifdef FIXED_LOCATION
Framework::FixedPosition::FixedPosition()
@@ -95,38 +98,20 @@ namespace
static const int BM_TOUCH_PIXEL_INCREASE = 20;
}
-pair<MwmSet::MwmLock, bool> Framework::RegisterMap(string const & file)
+pair<MwmSet::MwmLock, bool> Framework::RegisterMap(LocalCountryFile const & 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;
+ string const countryFileName = localFile.GetCountryFile().GetNameWithoutExt();
+ LOG(LINFO, ("Loading map:", countryFileName));
+ return m_model.RegisterMap(localFile);
}
-void Framework::DeregisterMap(string const & file) { m_model.DeregisterMap(file); }
-
-void Framework::OnLocationError(TLocationError /*error*/)
+void Framework::DeregisterMap(CountryFile const & countryFile)
{
+ m_model.DeregisterMap(countryFile);
}
+void Framework::OnLocationError(TLocationError /*error*/) {}
+
void Framework::OnLocationUpdate(GpsInfo const & info)
{
#ifdef FIXED_LOCATION
@@ -198,32 +183,6 @@ 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),
@@ -280,6 +239,7 @@ 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.
@@ -292,7 +252,7 @@ Framework::Framework()
LOG(LDEBUG, ("Maps initialized"));
// Init storage with needed callback.
- m_storage.Init(bind(&Framework::UpdateAfterDownload, this, _1, _2));
+ m_storage.Init(bind(&Framework::UpdateAfterDownload, this, _1));
LOG(LDEBUG, ("Storage initialized"));
#ifdef USE_PEDESTRIAN_ROUTER
@@ -308,6 +268,7 @@ Framework::Framework()
Framework::~Framework()
{
delete m_benchmarkEngine;
+ m_model.SetOnMapDeregisteredCallback(nullptr);
}
void Framework::DrawSingleFrame(m2::PointD const & center, int zoomModifier,
@@ -395,44 +356,34 @@ double Framework::GetVisualScale() const
return m_scales.GetVisualScale();
}
-void Framework::DeleteCountry(TIndex const & index, TMapOptions opt)
+void Framework::DeleteCountry(storage::TIndex const & index, TMapOptions opt)
{
- if (HasOptions(opt, TMapOptions::EMap))
- opt = TMapOptions::EMapWithCarRouting;
-
- if (!m_storage.DeleteFromDownloader(index))
+ switch (opt)
{
- CountryFile const & file = m_storage.CountryByIndex(index).GetFile();
-
- if (HasOptions(opt, TMapOptions::EMap))
+ case TMapOptions::ENothing:
+ return;
+ case TMapOptions::EMap: // fall through
+ case TMapOptions::EMapWithCarRouting:
{
- if (m_model.DeleteMap(file.GetFileWithExt(TMapOptions::EMap)))
- InvalidateRect(GetCountryBounds(file.GetFileWithoutExt()), true);
+ 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 (HasOptions(opt, TMapOptions::ECarRouting))
- m_routingSession.DeleteIndexFile(file.GetFileWithExt(TMapOptions::ECarRouting));
-
- m_storage.NotifyStatusChanged(index);
-
- DeleteCountryIndexes(m_storage.CountryFileNameWithoutExt(index));
+ case TMapOptions::ECarRouting:
+ m_routingSession.Reset();
+ m_storage.DeleteCountry(index, opt);
+ return;
}
}
-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);
@@ -459,7 +410,8 @@ m2::RectD Framework::GetCountryBounds(string const & file) const
m2::RectD Framework::GetCountryBounds(TIndex const & index) const
{
- return GetCountryBounds(m_storage.CountryFileNameWithoutExt(index));
+ CountryFile const & file = m_storage.GetCountryFile(index);
+ return GetCountryBounds(file.GetNameWithoutExt());
}
void Framework::ShowCountry(TIndex const & index)
@@ -469,72 +421,57 @@ void Framework::ShowCountry(TIndex const & index)
ShowRectEx(GetCountryBounds(index));
}
-void Framework::UpdateAfterDownload(string const & fileName, TMapOptions opt)
+void Framework::UpdateAfterDownload(LocalCountryFile const & localFile)
{
- 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);
-
- // Routing index doesn't exist for this map files.
- }
-
- // 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);
- }
-
- GetSearchEngine()->ClearViewportsCache();
- }
+ // TODO (@ldragunov, @gorshenin): rewrite routing session to use MwmLocks. Thus,
+ // it won' be needed to reset it after maps update.
+ m_routingSession.Reset();
- // Replace routing file.
- if (HasOptions(opt, TMapOptions::ECarRouting))
- {
- string routingName = fileName + ROUTING_FILE_EXTENSION;
- m_routingSession.DeleteIndexFile(routingName);
+ if (!HasOptions(localFile.GetFiles(), TMapOptions::EMap))
+ return;
- routingName = GetPlatform().WritableDir() + routingName;
- VERIFY(my::RenameFileX(routingName + READY_FILE_EXTENSION, routingName), ());
- }
+ // 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();
+}
- string countryName(fileName);
- my::GetNameWithoutExt(countryName);
- DeleteCountryIndexes(countryName);
+void Framework::OnMapDeregistered(platform::LocalCountryFile const & localFile)
+{
+ m_storage.DeleteCustomCountryVersion(localFile);
}
void Framework::RegisterAllMaps()
{
- ASSERT(!Storage().IsDownloadInProgress(),
- ("Registering maps while map downloading leads to removing downloading maps from ActiveMapsListener::m_items."));
- //ASSERT(m_model.IsEmpty(), ());
+ ASSERT(!m_storage.IsDownloadInProgress(),
+ ("Registering maps while map downloading leads to removing downloading maps from "
+ "ActiveMapsListener::m_items."));
+
+ platform::CleanupMapsDirectory();
+ m_storage.RegisterAllLocalMaps();
- int minVersion = numeric_limits<int>::max();
+ int minFormat = numeric_limits<int>::max();
+ vector<CountryFile> maps;
+ m_storage.GetLocalMaps(maps);
- vector<string> maps;
- GetMaps(maps);
- for_each(maps.begin(), maps.end(), [&](string const & file)
+ for (CountryFile const & countryFile : maps)
{
- 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));
- }
- });
+ 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));
+ }
m_countryTree.Init(maps);
- GetSearchEngine()->SupportOldFormat(minVersion < version::v3);
+ GetSearchEngine()->SupportOldFormat(minFormat < version::v3);
}
void Framework::DeregisterAllMaps()
@@ -2212,22 +2149,27 @@ 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)
{
- auto const countryFileFn = [this](m2::PointD const & pt)
- {
- return GetSearchEngine()->GetCountryFile(pt) + DATA_FILE_EXTENSION;
- };
- router = CreatePedestrianAStarBidirectionalRouter(m_model.GetIndex(), countryFileFn, routingVisualizerFn);
+ router = CreatePedestrianAStarBidirectionalRouter(m_model.GetIndex(), countryFileGetter,
+ routingVisualizerFn);
}
else
{
- auto const countryFileFn = [this](m2::PointD const & pt)
- {
- return GetSearchEngine()->GetCountryFile(pt);
- };
- router.reset(new OsrmRouter(&m_model.GetIndex(), countryFileFn, routingVisualizerFn));
+ router.reset(new OsrmRouter(&m_model.GetIndex(), countryFileGetter, localFileGetter,
+ routingVisualizerFn));
}
m_routingSession.SetRouter(move(router), routingStatisticsFn);
diff --git a/map/framework.hpp b/map/framework.hpp
index d0e6a723b2..89f0541bda 100644
--- a/map/framework.hpp
+++ b/map/framework.hpp
@@ -135,8 +135,10 @@ protected:
static const int TOUCH_PIXEL_RADIUS = 20;
/// This function is called by m_storage to notify that country downloading is finished.
- /// @param[in] file Country file name (without extensions).
- void UpdateAfterDownload(string const & file, TMapOptions opt);
+ 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);
//my::Timer m_timer;
inline double ElapsedSeconds() const
@@ -155,10 +157,7 @@ protected:
void ClearAllCaches();
- void DeregisterMap(string const & file);
-
- /// Deletes user calculated indexes on country updates
- void DeleteCountryIndexes(string const & mwmName);
+ void DeregisterMap(platform::CountryFile const & countryFile);
public:
Framework();
@@ -189,11 +188,6 @@ 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();
@@ -204,7 +198,7 @@ public:
///
/// @return True and inner mwm data version from header in version
/// or false in case of errors.
- pair<MwmSet::MwmLock, bool> RegisterMap(string const & file);
+ pair<MwmSet::MwmLock, bool> RegisterMap(platform::LocalCountryFile const & localFile);
//@}
/// Deletes all disk files corresponding to country.
diff --git a/map/map_tests/bookmarks_test.cpp b/map/map_tests/bookmarks_test.cpp
index 8edd6d69f6..51cc6e854b 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("minsk-pass.mwm");
+ fm.RegisterMap(platform::LocalCountryFile::MakeForTesting("minsk-pass"));
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 22529e5752..974cb436a4 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(file + DATA_FILE_EXTENSION));
+ UNUSED_VALUE(src.RegisterMap(platform::LocalCountryFile::MakeForTesting(file)));
// 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 6036885f89..ce23dc7eea 100644
--- a/map/mwm_tests/mwm_foreach_test.cpp
+++ b/map/mwm_tests/mwm_foreach_test.cpp
@@ -247,17 +247,18 @@ public:
}
};
-void RunTest(string const & file)
+void RunTest(string const & countryFileName)
{
model::FeaturesFetcher src1;
src1.InitClassificator();
- UNUSED_VALUE(src1.RegisterMap(file));
+ platform::LocalCountryFile localFile(platform::LocalCountryFile::MakeForTesting(countryFileName));
+ UNUSED_VALUE(src1.RegisterMap(localFile));
vector<m2::RectD> rects;
rects.push_back(src1.GetWorldRect());
- ModelReaderPtr reader = GetPlatform().GetReader(file);
+ ModelReaderPtr reader = GetPlatform().GetCountryReader(localFile, TMapOptions::EMap);
while (!rects.empty())
{
@@ -301,15 +302,10 @@ void RunTest(string const & file)
}
}
-void RunTestForChoice(string const & fName)
-{
- RunTest(fName + DATA_FILE_EXTENSION);
-}
-
}
UNIT_TEST(ForEach_QueryResults)
{
- RunTestForChoice("minsk-pass");
+ RunTest("minsk-pass");
//RunTestForChoice("london-center");
}
diff --git a/map/mwm_tests/mwm_index_test.cpp b/map/mwm_tests/mwm_index_test.cpp
index 5f3b3e509e..700d1ddf12 100644
--- a/map/mwm_tests/mwm_index_test.cpp
+++ b/map/mwm_tests/mwm_index_test.cpp
@@ -36,10 +36,11 @@ public:
}
};
-bool RunTest(string const & fileName, int lowS, int highS)
+bool RunTest(string const & countryFileName, int lowS, int highS)
{
model::FeaturesFetcher src;
- pair<MwmSet::MwmLock, bool> const p = src.RegisterMap(fileName);
+ pair<MwmSet::MwmLock, bool> const p =
+ src.RegisterMap(platform::LocalCountryFile::MakeForTesting(countryFileName));
if (!p.second)
return false;
MwmSet::MwmLock const & lock = p.first;
@@ -66,8 +67,8 @@ UNIT_TEST(ForEachFeatureID_Test)
classificator::Load();
/// @todo Uncomment World* checking after next map data update.
- //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()), ());
+ // 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()), ());
}
diff --git a/map/routing_session.cpp b/map/routing_session.cpp
index 64aa286261..431f13ee00 100644
--- a/map/routing_session.cpp
+++ b/map/routing_session.cpp
@@ -8,12 +8,10 @@
#include "coding/internal/file_data.hpp"
-
using namespace location;
namespace routing
{
-
static int const ON_ROUTE_MISSED_COUNT = 5;
RoutingSession::RoutingSession()
@@ -46,7 +44,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);
@@ -67,6 +65,8 @@ 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,14 +196,8 @@ void RoutingSession::SetRouter(unique_ptr<IRouter> && router, TRoutingStatistics
m_router.reset(new AsyncRouter(move(router), routingStatisticsFn));
}
-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
+void RoutingSession::MatchLocationToRoute(location::GpsInfo & location,
+ location::RouteMatchingInfo & routeMatchingInfo) const
{
if (m_state != State::OnRoute)
return;
@@ -212,5 +206,4 @@ void RoutingSession::MatchLocationToRoute(location::GpsInfo & location, location
UNUSED_VALUE(guard);
m_route.MatchLocationToRoute(location, routeMatchingInfo);
}
-
}
diff --git a/map/routing_session.hpp b/map/routing_session.hpp
index fd1abdb910..98a7606ae3 100644
--- a/map/routing_session.hpp
+++ b/map/routing_session.hpp
@@ -13,24 +13,25 @@
#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
};
/*
@@ -47,7 +48,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();
@@ -55,7 +56,8 @@ 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; }
@@ -68,8 +70,8 @@ public:
State OnLocationPositionChanged(m2::PointD const & position, location::GpsInfo const & info);
void GetRouteFollowingInfo(location::FollowingInfo & info) const;
- void DeleteIndexFile(string const & fileName);
- void MatchLocationToRoute(location::GpsInfo & location, location::RouteMatchingInfo & routeMatchingInfo) const;
+ void MatchLocationToRoute(location::GpsInfo & location,
+ location::RouteMatchingInfo & routeMatchingInfo) const;
// TODO (Dragunov) Make activation of the pedestrian routing
void ActivateAdditionalFeatures() {}
@@ -81,12 +83,13 @@ 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);
@@ -103,5 +106,4 @@ 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 3cffe31eaa..fe9e956d73 100644
--- a/pedestrian_routing_benchmarks/pedestrian_routing_benchmarks.cpp
+++ b/pedestrian_routing_benchmarks/pedestrian_routing_benchmarks.cpp
@@ -17,11 +17,13 @@
#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
@@ -69,7 +71,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.GetMwmIdByFileName(MAP_FILE);
+ MwmSet::MwmId const id = index.GetMwmIdByCountryFile(CountryFile(MAP_NAME));
TEST(id.IsAlive(), ());
routing::PedestrianModel const vehicleModel;
@@ -107,7 +109,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_FILE; };
+ auto const countryFileFn = [](m2::PointD const & /* point */) { return MAP_NAME; };
// find route by A*-bidirectional algorithm
routing::Route routeFoundByAstarBidirectional("");
@@ -127,9 +129,14 @@ 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(MAP_FILE));
- TEST(index.IsLoaded(MAP_NAME), ());
+ UNUSED_VALUE(index.RegisterMap(localFile));
+ TEST(index.IsLoaded(countryFile), ());
+ MwmSet::MwmId const id = index.GetMwmIdByCountryFile(countryFile);
+ TEST(id.IsAlive(), ());
vector<pair<routing::Edge, m2::PointD>> startEdges;
GetNearestPedestrianEdges(index, startPos, startEdges);
@@ -139,8 +146,10 @@ 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);
}
@@ -149,11 +158,13 @@ void TestTwoPoints(m2::PointD const & startPos, m2::PointD const & finalPos)
{
classificator::Load();
- Index index;
- UNUSED_VALUE(index.RegisterMap(MAP_FILE));
- TEST(index.IsLoaded(MAP_NAME), ());
+ CountryFile countryFile(MAP_NAME);
+ LocalCountryFile localFile = LocalCountryFile::MakeForTesting(MAP_NAME);
- MwmSet::MwmId const id = index.GetMwmIdByFileName(MAP_FILE);
+ Index index;
+ UNUSED_VALUE(index.RegisterMap(localFile));
+ TEST(index.IsLoaded(countryFile), ());
+ MwmSet::MwmId const id = index.GetMwmIdByCountryFile(countryFile);
TEST(id.IsAlive(), ());
TestRouters(index, startPos, finalPos);
diff --git a/platform/country_defines.cpp b/platform/country_defines.cpp
index 5a3ab9e8f5..927f883709 100644
--- a/platform/country_defines.cpp
+++ b/platform/country_defines.cpp
@@ -2,14 +2,25 @@
#include "base/assert.hpp"
-bool HasOptions(TMapOptions options, TMapOptions bits)
+bool HasOptions(TMapOptions mask, TMapOptions options)
{
- return (static_cast<uint8_t>(options) & static_cast<uint8_t>(bits)) == static_cast<uint8_t>(bits);
+ return (static_cast<uint8_t>(mask) & static_cast<uint8_t>(options)) ==
+ static_cast<uint8_t>(options);
}
-TMapOptions SetOptions(TMapOptions options, TMapOptions bits)
+TMapOptions SetOptions(TMapOptions mask, TMapOptions options)
{
- return static_cast<TMapOptions>(static_cast<uint8_t>(options) | static_cast<uint8_t>(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));
}
string DebugPrint(TMapOptions options)
@@ -24,8 +35,5 @@ 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 11e6f97842..5c010cbd13 100644
--- a/platform/country_defines.hpp
+++ b/platform/country_defines.hpp
@@ -10,8 +10,12 @@ enum class TMapOptions : uint8_t
EMapWithCarRouting = 0x3
};
-bool HasOptions(TMapOptions options, TMapOptions bits);
+bool HasOptions(TMapOptions mask, TMapOptions options);
-TMapOptions SetOptions(TMapOptions options, TMapOptions bits);
+TMapOptions SetOptions(TMapOptions mask, TMapOptions options);
+
+TMapOptions UnsetOptions(TMapOptions mask, TMapOptions options);
+
+TMapOptions LeastSignificantOption(TMapOptions mask);
string DebugPrint(TMapOptions options);
diff --git a/platform/country_file.cpp b/platform/country_file.cpp
index 8fffb2a52d..b7f4210e8b 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 b730395ad5..2ccf776392 100644
--- a/platform/local_country_file.cpp
+++ b/platform/local_country_file.cpp
@@ -34,20 +34,23 @@ void LocalCountryFile::SyncWithDisk()
Platform & platform = GetPlatform();
- if (platform.GetFileSizeByName(GetPath(TMapOptions::EMap), m_mapSize))
+ if (platform.GetFileSizeByFullPath(GetPath(TMapOptions::EMap), m_mapSize))
m_files = SetOptions(m_files, TMapOptions::EMap);
string const routingPath = GetPath(TMapOptions::ECarRouting);
- if (platform.GetFileSizeByName(routingPath, m_routingSize))
+ if (platform.GetFileSizeByFullPath(routingPath, m_routingSize))
m_files = SetOptions(m_files, TMapOptions::ECarRouting);
}
-void LocalCountryFile::DeleteFromDisk()
+void LocalCountryFile::DeleteFromDisk(TMapOptions files) const
{
for (TMapOptions file : {TMapOptions::EMap, TMapOptions::ECarRouting})
{
- if (OnDisk(file))
- VERIFY(my::DeleteFileX(GetPath(file)), (file, "from", *this, "wasn't deleted from disk."));
+ if (OnDisk(file) && HasOptions(files, file))
+ {
+ if (!my::DeleteFileX(GetPath(file)))
+ LOG(LERROR, (file, "from", *this, "wasn't deleted from disk."));
+ }
}
}
diff --git a/platform/local_country_file.hpp b/platform/local_country_file.hpp
index c73975f772..1a2afa0180 100644
--- a/platform/local_country_file.hpp
+++ b/platform/local_country_file.hpp
@@ -25,8 +25,9 @@ public:
// their sizes etc. with disk.
void SyncWithDisk();
- // Removes known country files from disk.
- void DeleteFromDisk();
+ // Removes specified files from disk if they're known for LocalCountryFile, i.e.
+ // were found by previous SyncWithDisk() call.
+ void DeleteFromDisk(TMapOptions files) const;
// Returns path to a file. Return value may be empty until
// SyncWithDisk() is called.
@@ -47,6 +48,7 @@ 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 87e76142d3..b5ded8a11c 100644
--- a/platform/local_country_file_utils.cpp
+++ b/platform/local_country_file_utils.cpp
@@ -1,12 +1,16 @@
#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
{
@@ -26,10 +30,11 @@ void CleanupMapsDirectory()
// Remove partially downloaded maps.
{
Platform::FilesList files;
- string const regexp = "\\" DATA_FILE_EXTENSION "\\.(downloading2?$|resume2?$)";
+ // .(downloading|resume|ready)[0-9]?$
+ string const regexp = "\\.(downloading|resume|ready)[0-9]?$";
platform.GetFilesByRegExp(mapsDir, regexp, files);
for (string const & file : files)
- FileWriter::DeleteFileX(file);
+ FileWriter::DeleteFileX(my::JoinFoldersToPath(mapsDir, file));
}
// Find and remove Brazil and Japan maps.
@@ -41,7 +46,7 @@ void CleanupMapsDirectory()
if (countryFile.GetNameWithoutExt() == "Japan" || countryFile.GetNameWithoutExt() == "Brazil")
{
localFile.SyncWithDisk();
- localFile.DeleteFromDisk();
+ localFile.DeleteFromDisk(TMapOptions::EMapWithCarRouting);
}
}
@@ -104,9 +109,10 @@ void FindAllLocalMaps(vector<LocalCountryFile> & localFiles)
{
int64_t version;
if (ParseVersion(subdir, version))
- FindAllLocalMapsInDirectory(my::JoinFoldersToPath(directory, subdir), version, allFiles);
+ FindAllLocalMapsInDirectory(my::JoinFoldersToPath(directory, subdir), version, localFiles);
}
}
+
#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})
@@ -135,7 +141,6 @@ void FindAllLocalMaps(vector<LocalCountryFile> & localFiles)
}
}
#endif // defined(OMIM_OS_ANDROID)
-
localFiles.insert(localFiles.end(), allFiles.begin(), allFiles.end());
}
@@ -143,6 +148,7 @@ 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)
{
@@ -162,22 +168,29 @@ 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));
- switch (platform.MkDir(directory))
+ Platform::EError ret = platform.MkDir(directory);
+ switch (ret)
{
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 ||
- type != Platform::FILE_TYPE_DIRECTORY)
+ if (Platform::GetFileType(directory, type) != Platform::ERR_OK)
{
+ 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 a5b0f720a5..bfffb65a7c 100644
--- a/platform/platform.cpp
+++ b/platform/platform.cpp
@@ -1,5 +1,7 @@
#include "platform/platform.hpp"
+#include "platform/local_country_file.hpp"
+
#include "coding/sha2.hpp"
#include "coding/base64.hpp"
#include "coding/file_name_utils.hpp"
@@ -147,3 +149,9 @@ 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 91f86740d7..7effb78d90 100644
--- a/platform/platform.hpp
+++ b/platform/platform.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "platform/country_defines.hpp"
+
#include "coding/reader.hpp"
#include "base/exception.hpp"
@@ -12,10 +14,14 @@
#include "defines.hpp"
-
DECLARE_EXCEPTION(FileAbsentException, RootException);
DECLARE_EXCEPTION(NotImplementedException, RootException);
+namespace platform
+{
+class LocalCountryFile;
+}
+
class Platform
{
public:
@@ -109,6 +115,9 @@ 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 92e6fde61c..225547015e 100644
--- a/platform/platform_android.cpp
+++ b/platform/platform_android.cpp
@@ -20,8 +20,15 @@ Platform::Platform()
namespace
{
-
-enum SourceT { EXTERNAL_RESOURCE, RESOURCE, WRITABLE_PATH, SETTINGS_PATH, FULL_PATH };
+enum SourceT
+{
+ EXTERNAL_RESOURCE,
+ RESOURCE,
+ WRITABLE_PATH,
+ SETTINGS_PATH,
+ FULL_PATH,
+ SOURCE_COUNT
+};
bool IsResource(string const & file, string const & ext)
{
@@ -40,7 +47,8 @@ bool IsResource(string const & file, string const & ext)
return true;
}
-size_t GetSearchSources(string const & file, string const & searchScope, SourceT (&arr)[4])
+size_t GetSearchSources(string const & file, string const & searchScope,
+ SourceT (&arr)[SOURCE_COUNT])
{
size_t ret = 0;
@@ -88,7 +96,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[4];
+ SourceT sources[SOURCE_COUNT];
size_t n = 0;
if (searchScope.empty())
@@ -172,6 +180,7 @@ 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;
}
@@ -238,8 +247,9 @@ bool Platform::GetFileSizeByName(string const & fileName, uint64_t & size) const
size = ReaderPtr<Reader>(GetReader(fileName)).Size();
return true;
}
- catch (RootException const &)
+ catch (RootException const & ex)
{
+ LOG(LWARNING, ("Can't get file size for:", fileName));
return false;
}
}
@@ -249,7 +259,7 @@ Platform::EError Platform::MkDir(string const & dirName) const
if (mkdir(dirName.c_str(), 0755))
{
LOG(LWARNING, ("Can't create directory: ", dirName));
- return Platform::ERR_UNKNOWN;
+ return ErrnoToError();
}
return Platform::ERR_OK;
}
diff --git a/platform/platform_ios.mm b/platform/platform_ios.mm
index 5fd1310059..cb14de0171 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 Platform::ERR_UNKNOWN;
+ return ErrnoToError();
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 5594a4e63f..46981142f6 100644
--- a/platform/platform_tests/local_country_file_tests.cpp
+++ b/platform/platform_tests/local_country_file_tests.cpp
@@ -7,6 +7,7 @@
#include "coding/file_name_utils.hpp"
#include "coding/file_writer.hpp"
+#include "coding/internal/file_data.hpp"
#include "base/scope_guard.hpp"
@@ -26,24 +27,30 @@ 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:
- ScopedTestDir(string const & path) : m_path(path), m_reset(false)
+ /// 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)
{
Platform & platform = GetPlatform();
- Platform::EError ret = platform.MkDir(m_path);
+ Platform::EError ret = platform.MkDir(GetFullPath());
switch (ret)
{
case Platform::ERR_OK:
break;
case Platform::ERR_FILE_ALREADY_EXISTS:
Platform::EFileType type;
- TEST_EQUAL(Platform::ERR_OK, Platform::GetFileType(m_path, type), ());
+ TEST_EQUAL(Platform::ERR_OK, Platform::GetFileType(GetFullPath(), type), ());
TEST_EQUAL(Platform::FILE_TYPE_DIRECTORY, type, ());
break;
default:
- CHECK(false, ("Can't create directory:", m_path, "error:", ret));
+ CHECK(false, ("Can't create directory:", GetFullPath(), "error:", ret));
break;
}
}
@@ -53,43 +60,100 @@ public:
if (m_reset)
return;
- Platform::EError ret = Platform::RmDir(m_path);
+ string const fullPath = GetFullPath();
+ Platform::EError ret = Platform::RmDir(fullPath);
switch (ret)
{
case Platform::ERR_OK:
break;
case Platform::ERR_FILE_DOES_NOT_EXIST:
- LOG(LWARNING, (m_path, "was deleted before destruction of ScopedTestDir."));
+ LOG(LWARNING, (fullPath, "was deleted before destruction of ScopedTestDir."));
break;
case Platform::ERR_DIRECTORY_NOT_EMPTY:
- LOG(LWARNING, ("There are files in", m_path));
+ LOG(LWARNING, ("There are files in", fullPath));
break;
default:
- LOG(LWARNING, ("Platform::RmDir() error:", ret));
+ LOG(LWARNING, ("Platform::RmDir() error for", fullPath, ":", ret));
break;
}
}
inline void Reset() { m_reset = true; }
- inline string const GetPath() const { return m_path; }
+ inline string const & GetFullPath() const { return m_fullPath; }
+
+ inline string const & GetRelativePath() const { return m_relativePath; }
+
+ bool Exists() const { return GetPlatform().IsFileExistsByFullPath(GetFullPath()); }
private:
- string const m_path;
+ string const m_fullPath;
+ string const m_relativePath;
bool m_reset;
DISALLOW_COPY_AND_MOVE(ScopedTestDir);
};
-void CreateTestFile(string const & testFile, string const & contents)
+class ScopedTestFile
{
+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());
}
- TEST(Platform::IsFileExistsByFullPath(testFile), ("Can't create test file", testFile));
+
+ ~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();
}
+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
@@ -160,17 +224,12 @@ 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), ());
- CreateTestFile(testMapFile, "map");
+ ScopedTestFile testMapFile(countryFile.GetNameWithExt(TMapOptions::EMap), "map");
localFile.SyncWithDisk();
TEST(localFile.OnDisk(TMapOptions::EMap), ());
@@ -178,7 +237,7 @@ UNIT_TEST(LocalCountryFile_DiskFiles)
TEST(!localFile.OnDisk(TMapOptions::EMapWithCarRouting), ());
TEST_EQUAL(3, localFile.GetSize(TMapOptions::EMap), ());
- CreateTestFile(testRoutingFile, "routing");
+ ScopedTestFile testRoutingFile(countryFile.GetNameWithExt(TMapOptions::ECarRouting), "routing");
localFile.SyncWithDisk();
TEST(localFile.OnDisk(TMapOptions::EMap), ());
@@ -188,14 +247,15 @@ UNIT_TEST(LocalCountryFile_DiskFiles)
TEST_EQUAL(7, localFile.GetSize(TMapOptions::ECarRouting), ());
TEST_EQUAL(10, localFile.GetSize(TMapOptions::EMapWithCarRouting), ());
- 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."));
+ 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();
}
-UNIT_TEST(LocalCountryFile_DirectoryCleanup)
+UNIT_TEST(LocalCountryFile_CleanupMapFiles)
{
Platform & platform = GetPlatform();
string const mapsDir = platform.WritableDir();
@@ -204,19 +264,19 @@ UNIT_TEST(LocalCountryFile_DirectoryCleanup)
CountryFile brazilFile("Brazil");
CountryFile irelandFile("Ireland");
- 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 testDir1("1");
+ LocalCountryFile japanLocalFile(testDir1.GetFullPath(), japanFile, 1 /* version */);
+ ScopedTestFile japanMapFile(testDir1, japanFile, TMapOptions::EMap, "Japan");
- ScopedTestDir testDir3(my::JoinFoldersToPath(mapsDir, "3"));
+ 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");
- LocalCountryFile irelandLocalFile(testDir2.GetPath(), irelandFile, 2 /* version */);
- CreateTestFile(irelandLocalFile.GetPath(TMapOptions::EMap), "Ireland");
+ ScopedTestDir testDir3("3");
+ // Check that FindAllLocalMaps()
vector<LocalCountryFile> localFiles;
FindAllLocalMaps(localFiles);
TEST(Contains(localFiles, japanLocalFile), (japanLocalFile));
@@ -227,20 +287,47 @@ UNIT_TEST(LocalCountryFile_DirectoryCleanup)
japanLocalFile.SyncWithDisk();
TEST_EQUAL(TMapOptions::ENothing, japanLocalFile.GetFiles(), ());
- TEST(!Platform::IsFileExistsByFullPath(testDir1.GetPath()), ("Empty directory wasn't removed."));
+ TEST(!testDir1.Exists(), ("Empty directory", testDir1, "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();
+ irelandLocalFile.DeleteFromDisk(TMapOptions::EMap);
+ TEST(!irelandMapFile.Exists(), (irelandMapFile));
+ irelandMapFile.Reset();
- TEST(!Platform::IsFileExistsByFullPath(testDir3.GetPath()), ("Empty directory wasn't removed."));
+ TEST(!testDir3.Exists(), ("Empty directory", testDir3, "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
@@ -253,37 +340,24 @@ UNIT_TEST(LocalCountryFile_DirectoryLookup)
CountryFile const irelandFile("Ireland");
CountryFile const netherlandsFile("Netherlands");
- 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));
+ ScopedTestDir testDir("test-dir");
- 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));
+ ScopedTestFile testIrelandMapFile(testDir, irelandFile, TMapOptions::EMap, "Ireland-map");
+ ScopedTestFile testNetherlandsMapFile(testDir, netherlandsFile, TMapOptions::EMap,
+ "Netherlands-map");
+ ScopedTestFile testNetherlandsRoutingFile(testDir, netherlandsFile, TMapOptions::ECarRouting,
+ "Netherlands-routing");
vector<LocalCountryFile> localFiles;
- FindAllLocalMapsInDirectory(testDir.GetPath(), 150309, localFiles);
+ FindAllLocalMapsInDirectory(testDir.GetFullPath(), 150309, localFiles);
sort(localFiles.begin(), localFiles.end());
for (LocalCountryFile & localFile : localFiles)
localFile.SyncWithDisk();
- LocalCountryFile expectedIrelandFile(testDir.GetPath(), irelandFile, 150309);
+ LocalCountryFile expectedIrelandFile(testDir.GetFullPath(), irelandFile, 150309);
expectedIrelandFile.m_files = TMapOptions::EMap;
- LocalCountryFile expectedNetherlandsFile(testDir.GetPath(), netherlandsFile, 150309);
+ LocalCountryFile expectedNetherlandsFile(testDir.GetFullPath(), netherlandsFile, 150309);
expectedNetherlandsFile.m_files = TMapOptions::EMapWithCarRouting;
vector<LocalCountryFile> expectedLocalFiles = {expectedIrelandFile, expectedNetherlandsFile};
@@ -301,12 +375,8 @@ UNIT_TEST(LocalCountryFile_AllLocalFilesLookup)
Platform & platform = GetPlatform();
- 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));
+ ScopedTestDir testDir("010101");
+ ScopedTestFile testItalyMapFile(testDir, italyFile, TMapOptions::EMap, "Italy-map");
vector<LocalCountryFile> localFiles;
FindAllLocalMaps(localFiles);
@@ -320,7 +390,7 @@ UNIT_TEST(LocalCountryFile_AllLocalFilesLookup)
CountryFile(WORLD_COASTS_FILE_NAME), 0 /* version */);
TEST_EQUAL(1, localFilesSet.count(expectedWorldCoastsFile), ());
- LocalCountryFile expectedItalyFile(testDir.GetPath(), italyFile, 10101);
+ LocalCountryFile expectedItalyFile(testDir.GetFullPath(), italyFile, 10101);
TEST_EQUAL(1, localFilesSet.count(expectedItalyFile), ());
}
@@ -335,17 +405,17 @@ UNIT_TEST(LocalCountryFile_PreparePlaceForCountryFiles)
TEST(italyLocalFile.get(), ());
TEST_EQUAL(expectedItalyFile, *italyLocalFile, ());
- ScopedTestDir directoryForV1(my::JoinFoldersToPath(platform.WritableDir(), "1"));
+ ScopedTestDir directoryForV1("1");
CountryFile germanyFile("Germany");
- LocalCountryFile expectedGermanyFile(directoryForV1.GetPath(), germanyFile, 1 /* version */);
+ LocalCountryFile expectedGermanyFile(directoryForV1.GetFullPath(), germanyFile, 1 /* version */);
shared_ptr<LocalCountryFile> germanyLocalFile =
PreparePlaceForCountryFiles(germanyFile, 1 /* version */);
TEST(germanyLocalFile.get(), ());
TEST_EQUAL(expectedGermanyFile, *germanyLocalFile, ());
CountryFile franceFile("France");
- LocalCountryFile expectedFranceFile(directoryForV1.GetPath(), franceFile, 1 /* version */);
+ LocalCountryFile expectedFranceFile(directoryForV1.GetFullPath(), 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 62586ba91e..adbb502500 100644
--- a/routing/osrm_router.cpp
+++ b/routing/osrm_router.cpp
@@ -4,6 +4,7 @@
#include "turns_generator.hpp"
#include "vehicle_model.hpp"
+#include "platform/country_file.hpp"
#include "platform/platform.hpp"
#include "geometry/angles.hpp"
@@ -349,9 +350,12 @@ public:
};
} // namespace
-OsrmRouter::OsrmRouter(Index const * index, TCountryFileFn const & fn,
+OsrmRouter::OsrmRouter(Index const * index, TCountryFileFn const & countryFileFn,
+ TCountryLocalFileFn const & countryLocalFileFn,
TRoutingVisualizerFn routingVisualization)
- : m_pIndex(index), m_indexManager(fn, index), m_routingVisualization(routingVisualization)
+ : m_pIndex(index),
+ m_indexManager(countryFileFn, countryLocalFileFn, index),
+ m_routingVisualization(routingVisualization)
{
}
diff --git a/routing/osrm_router.hpp b/routing/osrm_router.hpp
index 3eac5e9483..813fffd1cd 100644
--- a/routing/osrm_router.hpp
+++ b/routing/osrm_router.hpp
@@ -28,18 +28,17 @@ 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 & fn, TRoutingVisualizerFn routingVisualization = nullptr);
+ OsrmRouter(Index const * index, TCountryFileFn const & countryFileFn,
+ TCountryLocalFileFn const & countryLocalFileFn,
+ TRoutingVisualizerFn routingVisualization = nullptr);
virtual string GetName() const;
diff --git a/routing/road_graph_router.cpp b/routing/road_graph_router.cpp
index 7224e73d34..3f1a1b67cc 100644
--- a/routing/road_graph_router.cpp
+++ b/routing/road_graph_router.cpp
@@ -92,7 +92,8 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin
if (m_countryFileFn(startPoint) != mwmName)
return PointsInDifferentMWM;
- MwmSet::MwmLock const mwmLock = const_cast<Index&>(m_index).GetMwmLockByFileName(mwmName);
+ platform::CountryFile countryFile(mwmName);
+ MwmSet::MwmLock const mwmLock = const_cast<Index &>(m_index).GetMwmLockByCountryFile(countryFile);
if (!mwmLock.IsLocked())
return RouteFileNotExist;
diff --git a/routing/routing_mapping.cpp b/routing/routing_mapping.cpp
index 1d2001c578..a7c6f3bf97 100644
--- a/routing/routing_mapping.cpp
+++ b/routing/routing_mapping.cpp
@@ -10,34 +10,49 @@
#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(string const & fName, Index const * pIndex)
+RoutingMapping::RoutingMapping(CountryFile const & countryFile)
: m_mapCounter(0),
m_facadeCounter(0),
m_crossContextLoaded(0),
- m_baseName(fName),
+ 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_isValid(true),
m_error(IRouter::ResultCode::NoError)
{
Platform & pl = GetPlatform();
- string const mwmName = m_baseName + DATA_FILE_EXTENSION;
- string const fPath = pl.WritablePathForFile(mwmName + ROUTING_FILE_EXTENSION);
- if (!pl.IsFileExistsByFullPath(fPath))
+ if (!HasOptions(localFile.GetFiles(), TMapOptions::EMapWithCarRouting))
{
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:", fPath));
- m_container.Open(fPath);
+ LOG(LDEBUG, ("Load routing index for file:", routingFilePath));
+ m_container.Open(routingFilePath);
{
FileReader r1 = m_container.GetReader(VERSION_FILE_TAG);
ReaderSrc src1(r1);
- ModelReaderPtr r2 = FilesContainerR(pl.GetReader(mwmName)).GetReader(VERSION_FILE_TAG);
+ ModelReaderPtr r2 = FilesContainerR(pl.GetCountryReader(localFile, TMapOptions::EMap))
+ .GetReader(VERSION_FILE_TAG);
ReaderSrc src2(r2.GetPtr());
version::MwmVersion version1;
@@ -55,7 +70,7 @@ RoutingMapping::RoutingMapping(string const & fName, Index const * pIndex)
}
}
- m_mwmId = pIndex->GetMwmIdByFileName(mwmName);
+ m_mwmId = pIndex->GetMwmIdByCountryFile(localFile.GetCountryFile());
}
RoutingMapping::~RoutingMapping()
@@ -113,22 +128,33 @@ 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_countryFn(point));
+ return GetMappingByName(m_countryFileFn(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 new_mapping = make_shared<RoutingMapping>(mapName, m_index);
- m_mapping.insert(make_pair(mapName, new_mapping));
- return new_mapping;
+ TRoutingMappingPtr newMapping = make_shared<RoutingMapping>(*localFile, m_index);
+ m_mapping.insert(make_pair(mapName, newMapping));
+ return newMapping;
}
} // namespace routing
diff --git a/routing/routing_mapping.h b/routing/routing_mapping.h
index e791599f30..41d0b0da50 100644
--- a/routing/routing_mapping.h
+++ b/routing/routing_mapping.h
@@ -11,10 +11,17 @@
#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
@@ -24,7 +31,7 @@ struct RoutingMapping
CrossRoutingContextReader m_crossContext;
///@param fName: mwm file path
- RoutingMapping(string const & fName, Index const * pIndex);
+ RoutingMapping(platform::LocalCountryFile const & localFile, Index const * pIndex);
~RoutingMapping();
@@ -44,15 +51,21 @@ struct RoutingMapping
IRouter::ResultCode GetError() const {return m_error;}
- string const & GetName() const { return m_baseName; }
+ string const & GetName() const { return m_countryFileName; }
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_baseName;
+ string m_countryFileName;
FilesMappingContainer m_container;
Index::MwmId m_mwmId;
bool m_isValid;
@@ -86,8 +99,9 @@ public:
class RoutingIndexManager
{
public:
- RoutingIndexManager(TCountryFileFn const & fn, Index const * index)
- : m_countryFn(fn), m_index(index)
+ RoutingIndexManager(TCountryFileFn const & countryFileFn,
+ TCountryLocalFileFn const & countryLocalFileFn, Index const * index)
+ : m_countryFileFn(countryFileFn), m_countryLocalFileFn(countryLocalFileFn), m_index(index)
{
ASSERT(index, ());
}
@@ -105,9 +119,10 @@ public:
void Clear() { m_mapping.clear(); }
private:
- TCountryFileFn m_countryFn;
- Index const * m_index;
+ TCountryFileFn m_countryFileFn;
+ TCountryLocalFileFn m_countryLocalFileFn;
unordered_map<string, TRoutingMappingPtr> m_mapping;
+ Index const * m_index;
};
} // namespace routing
diff --git a/search/search_query.cpp b/search/search_query.cpp
index 0a5eab18d3..12741b473b 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->GetFileName();
+ country = m_pFV->GetCountryFileName();
}
public:
@@ -1659,11 +1659,14 @@ void Query::SearchAddress(Results & res)
{
MwmSet::MwmId id(info);
Index::MwmLock const mwmLock(const_cast<Index &>(*m_pIndex), id);
- string fileName;
if (mwmLock.IsLocked())
- fileName = mwmLock.GetValue<MwmValue>()->GetFileName();
- if (m_pInfoGetter->IsBelongToRegion(fileName, region.m_ids))
- SearchInMWM(mwmLock, params);
+ {
+ platform::CountryFile const & countryFile =
+ mwmLock.GetValue<MwmValue>()->GetCountryFile();
+ string const countryFileName = countryFile.GetNameWithoutExt();
+ if (m_pInfoGetter->IsBelongToRegion(countryFileName, region.m_ids))
+ SearchInMWM(mwmLock, params);
+ }
}
}
}
@@ -2108,9 +2111,8 @@ void Query::SearchInMWM(Index::MwmLock const & mwmLock, Params const & params,
TrieRootPrefix(*pLangRoot, edge),
filter, categoriesHolder, emitter);
- LOG(LDEBUG, ("Country", pMwm->GetFileName(),
- "Lang", StringUtf8Multilang::GetLangByCode(lang),
- "Matched", emitter.GetCount()));
+ LOG(LDEBUG, ("Country", pMwm->GetCountryFile().GetNameWithoutExt(), "Lang",
+ StringUtf8Multilang::GetLangByCode(lang), "Matched", emitter.GetCount()));
emitter.Reset();
}
@@ -2193,8 +2195,11 @@ 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>()->GetFileName() == fileName)
+ if (mwmLock.IsLocked() &&
+ mwmLock.GetValue<MwmValue>()->GetCountryFile().GetNameWithoutExt() == 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 1f03cb824d..eae291fb9a 100644
--- a/search/search_tests/house_detector_tests.cpp
+++ b/search/search_tests/house_detector_tests.cpp
@@ -17,6 +17,7 @@
#include "std/iostream.hpp"
#include "std/fstream.hpp"
+using platform::LocalCountryFile;
class StreetIDsByName
{
@@ -183,7 +184,8 @@ UNIT_TEST(HS_StreetsMerge)
classificator::Load();
Index index;
- pair<MwmSet::MwmLock, bool> const p = index.Register("minsk-pass.mwm");
+ pair<MwmSet::MwmLock, bool> const p =
+ index.Register(LocalCountryFile::MakeForTesting("minsk-pass"));
TEST(p.first.IsLocked(), ());
TEST(p.second, ());
@@ -272,7 +274,8 @@ UNIT_TEST(HS_FindHouseSmoke)
classificator::Load();
Index index;
- pair<MwmSet::MwmLock, bool> const p = index.Register("minsk-pass.mwm");
+ pair<MwmSet::MwmLock, bool> const p =
+ index.Register(LocalCountryFile::MakeForTesting("minsk-pass"));
TEST(p.first.IsLocked(), ());
TEST(p.second, ());
@@ -345,10 +348,7 @@ 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(country + ".mwm");
+ pair<MwmSet::MwmLock, bool> const p = index.Register(LocalCountryFile::MakeForTesting(country));
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 30182f7267..62efda0f5e 100644
--- a/search/search_tests/locality_finder_test.cpp
+++ b/search/search_tests/locality_finder_test.cpp
@@ -5,6 +5,10 @@
#include "search/locality_finder.hpp"
+#include "platform/country_file.hpp"
+#include "platform/local_country_file.hpp"
+#include "platform/platform.hpp"
+
namespace
{
@@ -34,7 +38,8 @@ void doTests2(search::LocalityFinder & finder, vector<m2::PointD> const & input,
UNIT_TEST(LocalityFinder)
{
Index index;
- pair<MwmSet::MwmLock, bool> const p = index.Register("World.mwm");
+ pair<MwmSet::MwmLock, bool> const p =
+ index.Register(platform::LocalCountryFile::MakeForTesting("World"));
TEST(p.second, ());
MwmSet::MwmLock const & lock = p.first;
TEST(lock.IsLocked(), ());
diff --git a/std/algorithm.hpp b/std/algorithm.hpp
index 426296336b..913e1c0482 100644
--- a/std/algorithm.hpp
+++ b/std/algorithm.hpp
@@ -6,6 +6,7 @@
#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 3e39eb674a..d2be152219 100644
--- a/storage/country.cpp
+++ b/storage/country.cpp
@@ -6,96 +6,19 @@
#include "3party/jansson/myjansson.hpp"
+using platform::CountryFile;
namespace storage
{
-
-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 Country::Size(TMapOptions opt) const
{
uint64_t size = 0;
- 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);
+ for (CountryFile const & file : m_files)
+ size += file.GetRemoteSize(opt);
+ return size;
}
+void Country::AddFile(CountryFile const & file) { m_files.push_back(file); }
////////////////////////////////////////////////////////////////////////
@@ -118,10 +41,9 @@ 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)
@@ -130,120 +52,133 @@ void LoadGroupImpl(int depth, json_t * group, ToDo & toDo)
}
template <class ToDo>
-int64_t LoadCountriesImpl(string const & jsonBuffer, ToDo & toDo)
+bool 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 & ex)
+ catch (my::Json::Exception const & e)
{
- LOG(LERROR, (ex.Msg()));
- return -1;
+ LOG(LERROR, (e.Msg()));
+ return false;
}
-
- return version;
}
namespace
{
- class DoStoreCountries
- {
- CountriesContainerT & m_cont;
- public:
- DoStoreCountries(CountriesContainerT & cont) : m_cont(cont) {}
+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)
+ void operator()(string const & name, string const & file, string const & flag, uint32_t mapSize,
+ uint32_t routingSize, int depth)
+ {
+ Country country(name, flag);
+ if (mapSize)
{
- Country country(name, flag);
- if (mapSize)
- country.AddFile(CountryFile(file, mapSize, routingSize));
- m_cont.AddAtDepth(depth, country);
+ CountryFile countryFile(file);
+ countryFile.SetRemoteSizes(mapSize, routingSize);
+ country.AddFile(countryFile);
}
- };
+ m_cont.AddAtDepth(depth, country);
+ }
+};
- class DoStoreFile2Info
- {
- map<string, CountryInfo> & m_file2info;
- string m_lastFlag;
+class DoStoreFile2Info
+{
+ map<string, CountryInfo> & m_file2info;
+ string m_lastFlag;
- public:
- DoStoreFile2Info(map<string, CountryInfo> & file2info) : m_file2info(file2info) {}
+public:
+ DoStoreFile2Info(map<string, CountryInfo> & file2info) : m_file2info(file2info) {}
- void operator() (string name, string file, string const & flag,
- uint32_t mapSize, uint32_t, int)
+ void operator()(string name, string file, string const & flag, uint32_t mapSize, uint32_t, int)
+ {
+ if (!flag.empty())
+ m_lastFlag = flag;
+
+ if (mapSize)
{
- if (!flag.empty())
- m_lastFlag = flag;
+ CountryInfo info;
- if (mapSize)
+ // if 'file' is empty - it's equal to 'name'
+ if (!file.empty())
{
- CountryInfo info;
+ // 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);
- // 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;
+ // Do not use 'name' here! It was swapped!
- // fill 'name' only when it differs with 'file'
- if (name != file)
- info.m_name.swap(name);
- }
- else
- file.swap(name);
+ ASSERT(!m_lastFlag.empty(), ());
+ info.m_flag = m_lastFlag;
- // Do not use 'name' here! It was swapped!
+ m_file2info[file] = info;
+ }
+ }
+};
- ASSERT ( !m_lastFlag.empty(), () );
- info.m_flag = m_lastFlag;
+class DoStoreCode2File
+{
+ multimap<string, string> & m_code2file;
- m_file2info[file] = info;
- }
- }
- };
+public:
+ DoStoreCode2File(multimap<string, string> & code2file) : m_code2file(code2file) {}
- class DoStoreCode2File
+ void operator()(string const &, string const & file, string const & flag, uint32_t, uint32_t, int)
{
- 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));
- }
- };
+ m_code2file.insert(make_pair(flag, file));
+ }
+};
}
int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries)
{
countries.Clear();
- DoStoreCountries doStore(countries);
- return LoadCountriesImpl(jsonBuffer, doStore);
+
+ 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;
}
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);
}
@@ -273,11 +208,12 @@ void SaveImpl(T const & v, json_t * jParent)
if (countriesCount > 0)
{
CountryFile const & file = v[i].Value().GetFile();
- string const & strFile = file.GetFileWithoutExt();
+ string const & strFile = file.GetNameWithoutExt();
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())
@@ -304,4 +240,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 0140722634..a51997be9d 100644
--- a/storage/country.hpp
+++ b/storage/country.hpp
@@ -1,8 +1,10 @@
#pragma once
-#include "storage/storage_defines.hpp"
-#include "storage/simple_tree.hpp"
#include "storage/country_decl.hpp"
+#include "storage/simple_tree.hpp"
+#include "storage/storage_defines.hpp"
+
+#include "platform/local_country_file.hpp"
#include "platform/country_defines.hpp"
@@ -15,91 +17,56 @@
#include "std/string.hpp"
#include "std/vector.hpp"
-
-namespace update { class SizeUpdater; }
+namespace update
+{
+class SizeUpdater;
+}
namespace storage
{
- /// Information about each file for a country
- class CountryFile
+/// 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
{
- string m_fileName; /// Same as id of country\region.
- uint32_t m_mapSize, m_routingSize;
+ ASSERT_EQUAL(m_files.size(), 1, (m_name));
+ return m_files.front();
+ }
- 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)
- {
- }
+ string const & Name() const { return m_name; }
+ string const & Flag() const { return m_flag; }
- void AssignSizes(uint32_t mapSize, uint32_t routingSize)
- {
- m_mapSize = mapSize;
- m_routingSize = routingSize;
- }
+ uint64_t Size(TMapOptions opt) const;
+};
- string GetFileWithExt(TMapOptions opt) const;
- string const & GetFileWithoutExt() const { return m_fileName; }
+typedef SimpleTree<Country> CountriesContainerT;
- uint32_t GetFileSize(TMapOptions opt) const;
- uint32_t GetRemoteSize(TMapOptions opt) const;
- };
+/// @return version of country file or -1 if error was encountered
+int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries);
- typedef buffer_vector<CountryFile, 1> FilesContainerT;
+void LoadCountryFile2CountryInfo(string const & jsonBuffer, map<string, CountryInfo> & id2info);
- /// 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);
-}
+void LoadCountryCode2File(string const & jsonBuffer, multimap<string, string> & code2file);
+
+bool SaveCountries(int64_t version, CountriesContainerT const & countries, string & jsonBuffer);
+} // namespace storage
diff --git a/storage/map_files_downloader.hpp b/storage/map_files_downloader.hpp
index ce0cf2fc1f..ad9224b426 100644
--- a/storage/map_files_downloader.hpp
+++ b/storage/map_files_downloader.hpp
@@ -2,6 +2,7 @@
#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
new file mode 100644
index 0000000000..9034370e77
--- /dev/null
+++ b/storage/queued_country.cpp
@@ -0,0 +1,52 @@
+#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
new file mode 100644
index 0000000000..de0f070273
--- /dev/null
+++ b/storage/queued_country.hpp
@@ -0,0 +1,31 @@
+#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 bad306c873..b9f7e75f58 100644
--- a/storage/storage.cpp
+++ b/storage/storage.cpp
@@ -4,17 +4,22 @@
#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_writer.hpp"
-#include "coding/file_reader.hpp"
#include "coding/file_container.hpp"
-#include "coding/url_encode.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/url_encode.hpp"
+
+#include "platform/local_country_file_utils.hpp"
#include "base/logging.hpp"
+#include "base/scope_guard.hpp"
#include "base/string_utils.hpp"
#include "std/algorithm.hpp"
@@ -25,688 +30,844 @@
#include "3party/Alohalytics/src/alohalytics.h"
using namespace downloader;
+using namespace platform;
namespace storage
{
- /*
- 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";
- }
- */
+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());
+}
- Storage::QueuedCountry::QueuedCountry(Storage const & storage, TIndex const & index,
- TMapOptions opt)
- : m_index(index), m_init(opt), m_left(opt)
+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})
{
- 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;
- }
+ if (HasOptions(opt, bit))
+ size += file->GetSize(bit);
}
+ return size;
+}
- void Storage::QueuedCountry::AddOptions(TMapOptions opt)
+uint64_t GetRemoteSize(CountryFile const & file, TMapOptions opt)
+{
+ uint64_t size = 0;
+ for (TMapOptions bit : {TMapOptions::EMap, TMapOptions::ECarRouting})
{
- 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]);
- }
- }
+ if (HasOptions(opt, bit))
+ size += file.GetRemoteSize(bit);
}
+ return size;
+}
- bool Storage::QueuedCountry::MoveNextFile()
- {
- if (m_current == m_left)
- return false;
+// 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);
+}
- /// 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;
- }
+class EqualFileName
+{
+ string const & m_name;
- bool Storage::QueuedCountry::Correct(TStatus currentStatus)
+public:
+ explicit EqualFileName(string const & name) : m_name(name) {}
+ bool operator()(SimpleTree<Country> const & node) const
{
- 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)
+ Country const & c = node.Value();
+ if (c.GetFilesCount() > 0)
+ return (c.GetFile().GetNameWithoutExt() == m_name);
+ else
return false;
+ }
+};
+} // namespace
-#ifdef DEBUG
- if (currentStatus == TStatus::EOnDiskOutOfDate && m_init == TMapOptions::EMap)
- ASSERT(m_pFile->GetFileSize(TMapOptions::ECarRouting) == 0, ());
-#endif
+Storage::Storage() : m_downloader(new HttpMapFilesDownloader()), m_currentSlotId(0)
+{
+ LoadCountriesFile(false /* forceReload */);
+}
- if (HasOptions(m_init, TMapOptions::ECarRouting))
- {
- ASSERT(HasOptions(m_init, TMapOptions::EMap), ());
+void Storage::Init(TUpdateAfterDownload const & updateFn) { m_updateAfterDownload = updateFn; }
- if (currentStatus == TStatus::EOnDisk)
- {
- if (m_pFile->GetFileSize(TMapOptions::ECarRouting) == 0)
- m_init = m_left = m_current = TMapOptions::ECarRouting;
- else
- return false;
- }
- }
+void Storage::RegisterAllLocalMaps()
+{
+ m_localFiles.clear();
+ m_localFilesForFakeCountries.clear();
- return true;
- }
+ vector<LocalCountryFile> localFiles;
+ FindAllLocalMaps(localFiles);
- uint64_t Storage::QueuedCountry::GetDownloadSize() const
+ auto compareByCountryAndVersion = [](LocalCountryFile const & lhs, LocalCountryFile const & rhs)
{
- return m_pFile->GetRemoteSize(m_current);
- }
+ if (lhs.GetCountryFile() != rhs.GetCountryFile())
+ return lhs.GetCountryFile() < rhs.GetCountryFile();
+ return lhs.GetVersion() > rhs.GetVersion();
+ };
- LocalAndRemoteSizeT Storage::QueuedCountry::GetFullSize() const
+ auto equalByCountry = [](LocalCountryFile const & lhs, LocalCountryFile const & rhs)
{
- 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]);
- }
- }
+ return lhs.GetCountryFile() == rhs.GetCountryFile();
+ };
- return res;
- }
+ sort(localFiles.begin(), localFiles.end(), compareByCountryAndVersion);
- size_t Storage::QueuedCountry::GetFullRemoteSize() const
+ auto i = localFiles.begin();
+ while (i != localFiles.end())
{
- size_t res = 0;
- TMapOptions const arr[] = { TMapOptions::EMap, TMapOptions::ECarRouting };
- for (size_t i = 0; i < ARRAY_SIZE(arr); ++i)
+ auto j = i + 1;
+ while (j != localFiles.end() && equalByCountry(*i, *j))
{
- if (HasOptions(m_init, arr[i]))
- res += m_pFile->GetRemoteSize(arr[i]);
+ LocalCountryFile & localFile = *j;
+ LOG(LINFO, ("Removing obsolete", localFile));
+ localFile.SyncWithDisk();
+ localFile.DeleteFromDisk(TMapOptions::EMapWithCarRouting);
+ ++j;
}
- return res;
+ 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;
}
+}
- string Storage::QueuedCountry::GetFileName() const
+void Storage::GetLocalMaps(vector<CountryFile> & maps)
+{
+ for (auto const & p : m_localFiles)
{
- return m_pFile->GetFileWithExt(m_current);
+ TIndex const & index = p.first;
+ maps.push_back(GetLatestLocalFile(index)->GetCountryFile());
}
+ for (auto const & p : m_localFilesForFakeCountries)
+ maps.push_back(p.second->GetCountryFile());
+}
- string Storage::QueuedCountry::GetMapFileName() const
+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 m_pFile->GetFileWithExt(TMapOptions::EMap);
+ return root[index.m_group];
}
-
- Storage::Storage() : m_downloader(new HttpMapFilesDownloader()), m_currentSlotId(0)
+ if (index.m_region == TIndex::INVALID ||
+ index.m_region >= static_cast<int>(root[index.m_group][index.m_country].SiblingsCount()))
{
- LoadCountriesFile(false);
+ return root[index.m_group][index.m_country];
+ }
+ return root[index.m_group][index.m_country][index.m_region];
+}
- if (Settings::IsFirstLaunchForDate(121031))
- {
- Platform & pl = GetPlatform();
- string const dir = pl.WritableDir();
+Country const & Storage::CountryByIndex(TIndex const & index) const
+{
+ return NodeFromIndex(m_countries, index).Value();
+}
- // Delete all: .mwm.downloading; .mwm.downloading2; .mwm.resume; .mwm.resume2
- string const regexp = "\\" DATA_FILE_EXTENSION "\\.(downloading2?$|resume2?$)";
+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);
+}
- Platform::FilesList files;
- pl.GetFilesByRegExp(dir, regexp, files);
+size_t Storage::CountriesCount(TIndex const & index) const
+{
+ return NodeFromIndex(m_countries, index).SiblingsCount();
+}
- for (size_t j = 0; j < files.size(); ++j)
- FileWriter::DeleteFileX(dir + files[j]);
- }
- }
+string const & Storage::CountryName(TIndex const & index) const
+{
+ return NodeFromIndex(m_countries, index).Value().Name();
+}
- void Storage::Init(TUpdateAfterDownload const & updateFn)
- {
- m_updateAfterDownload = updateFn;
- }
+string const & Storage::CountryFlag(TIndex const & index) const
+{
+ return NodeFromIndex(m_countries, index).Value().Flag();
+}
- CountriesContainerT const & NodeFromIndex(CountriesContainerT const & root, TIndex const & index)
+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)
{
- // 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];
- }
+ return LocalAndRemoteSizeT(GetLocalSize(localFile, opt), GetRemoteSize(countryFile, opt));
}
- Country const & Storage::CountryByIndex(TIndex const & index) const
+ LocalAndRemoteSizeT sizes(0, GetRemoteSize(countryFile, opt));
+ if (!m_downloader->IsIdle() && IsCountryFirstInQueue(index))
{
- return NodeFromIndex(m_countries, index).Value();
+ sizes.first = m_downloader->GetDownloadingProgress().first +
+ GetRemoteSize(countryFile, queuedCountry->GetDownloadedFiles());
}
+ return sizes;
+}
- void Storage::GetGroupAndCountry(TIndex const & index, string & group, string & country) const
- {
- string fName = CountryByIndex(index).GetFile().GetFileWithoutExt();
- CountryInfo::FileName2FullName(fName);
- CountryInfo::FullName2GroupAndMap(fName, group, country);
- }
+CountryFile const & Storage::GetCountryFile(TIndex const & index) const
+{
+ return CountryByIndex(index).GetFile();
+}
- size_t Storage::CountriesCount(TIndex const & index) const
+shared_ptr<LocalCountryFile> Storage::GetLatestLocalFile(CountryFile const & countryFile) const
+{
+ TIndex const index = FindIndexByFile(countryFile.GetNameWithoutExt());
{
- return NodeFromIndex(m_countries, index).SiblingsCount();
+ shared_ptr<LocalCountryFile> localFile = GetLatestLocalFile(index);
+ if (localFile.get())
+ return localFile;
}
-
- string const & Storage::CountryName(TIndex const & index) const
{
- return NodeFromIndex(m_countries, index).Value().Name();
+ auto const it = m_localFilesForFakeCountries.find(countryFile);
+ if (it != m_localFilesForFakeCountries.end())
+ return it->second;
}
+ return shared_ptr<LocalCountryFile>();
+}
- string const & Storage::CountryFlag(TIndex const & index) const
+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)
{
- return NodeFromIndex(m_countries, index).Value().Flag();
+ if (file->GetVersion() > latest->GetVersion())
+ latest = file;
}
+ return latest;
+}
- string Storage::CountryFileName(TIndex const & index, TMapOptions opt) const
+TStatus Storage::CountryStatus(TIndex const & index) const
+{
+ // Check if we already downloading this country or have it in the queue
+ if (IsCountryInQueue(index))
{
- return QueuedCountry(*this, index, opt).GetFileName();
+ if (IsCountryFirstInQueue(index))
+ return TStatus::EDownloading;
+ else
+ return TStatus::EInQueue;
}
- string const & Storage::CountryFileNameWithoutExt(TIndex const & index) const
- {
- return CountryByIndex(index).GetFile().GetFileWithoutExt();
- }
+ // Check if this country has failed while downloading.
+ if (m_failedCountries.count(index) > 0)
+ return TStatus::EDownloadFailed;
- string Storage::MapWithoutExt(string mapFile)
- {
- string::size_type const pos = mapFile.rfind(DATA_FILE_EXTENSION);
- if (pos != string::npos)
- mapFile.resize(pos);
- return std::move(mapFile);
- }
+ return TStatus::EUnknown;
+}
- LocalAndRemoteSizeT Storage::CountrySizeInBytes(TIndex const & index, TMapOptions opt) const
- {
- 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();
+TStatus Storage::CountryStatusEx(TIndex const & index) const
+{
+ return CountryStatusFull(index, CountryStatus(index));
+}
- return sizes;
- }
+void Storage::CountryStatusEx(TIndex const & index, TStatus & status, TMapOptions & options) const
+{
+ status = CountryStatusEx(index);
- TStatus Storage::CountryStatus(TIndex const & index) const
+ if (status == TStatus::EOnDisk || status == TStatus::EOnDiskOutOfDate)
{
- // 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;
- }
-
- // second, check if this country has failed while downloading
- if (m_failedCountries.count(index) > 0)
- return TStatus::EDownloadFailed;
+ options = TMapOptions::EMap;
- return TStatus::EUnknown;
+ 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);
}
+}
- TStatus Storage::CountryStatusEx(TIndex const & index) const
+void Storage::DownloadCountry(TIndex const & index, TMapOptions opt)
+{
+ opt = NormalizeDownloadFileSet(index, opt);
+ if (opt == TMapOptions::ENothing)
+ return;
+
+ if (QueuedCountry * queuedCountry = FindCountryInQueue(index))
{
- return CountryStatusFull(index, CountryStatus(index));
+ queuedCountry->AddOptions(opt);
+ return;
}
- void Storage::CountryStatusEx(TIndex const & index, TStatus & status, TMapOptions & options) const
- {
- status = CountryStatusEx(index);
+ m_failedCountries.erase(index);
+ m_queue.push_back(QueuedCountry(index, opt));
+ if (m_queue.size() == 1)
+ DownloadNextCountryFromQueue();
+ else
+ NotifyStatusChanged(index);
+}
- if (status == TStatus::EOnDisk || status == TStatus::EOnDiskOutOfDate)
- {
- options = TMapOptions::EMap;
+void Storage::DeleteCountry(TIndex const & index, TMapOptions opt)
+{
+ opt = NormalizeDeleteFileSet(opt);
+ DeleteCountryFiles(index, opt);
+ DeleteCountryFilesFromDownloader(index, opt);
+ KickDownloaderAfterDeletionOfCountryFiles(index);
+ NotifyStatusChanged(index);
+}
- 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::DeleteCustomCountryVersion(LocalCountryFile const & localFile)
+{
+ CountryFile const countryFile = localFile.GetCountryFile();
+ localFile.DeleteFromDisk(TMapOptions::EMapWithCarRouting);
- void Storage::DownloadCountry(TIndex const & index, TMapOptions opt)
{
- 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())
+ auto it = m_localFilesForFakeCountries.find(countryFile);
+ if (it != m_localFilesForFakeCountries.end())
{
- found->AddOptions(opt);
- return;
- }
-
- // remove it from failed list
- m_failedCountries.erase(index);
-
- // add it into the queue
- QueuedCountry cnt(*this, index, opt);
- if (!cnt.Correct(CountryStatusWithoutFailed(index)))
+ m_localFilesForFakeCountries.erase(it);
return;
- m_queue.push_back(cnt);
-
- // and start download if necessary
- if (m_queue.size() == 1)
- {
- DownloadNextCountryFromQueue();
- }
- else
- {
- // notify about "In Queue" status
- NotifyStatusChanged(index);
}
}
- void Storage::NotifyStatusChanged(TIndex const & index)
+ TIndex const index = FindIndexByFile(countryFile.GetNameWithoutExt());
+ if (!index.IsValid())
{
- for (CountryObservers const & o : m_observers)
- o.m_changeCountryFn(index);
+ LOG(LERROR, ("Removed files for an unknown country:", localFile));
+ return;
}
- void Storage::DownloadNextCountryFromQueue()
+ 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())
{
- if (!m_queue.empty())
- {
- QueuedCountry & cnt = m_queue.front();
+ LOG(LERROR, ("Deleted files of an unregistered country:", localFile));
+ return;
+ }
- m_countryProgress.first = 0;
- m_countryProgress.second = cnt.GetFullRemoteSize();
+ auto equalsToLocalFile = [&localFile](shared_ptr<LocalCountryFile> const & rhs)
+ {
+ return localFile == *rhs;
+ };
+ countryFilesIt->second.remove_if(equalsToLocalFile);
+}
- DownloadNextFile(cnt);
+void Storage::NotifyStatusChanged(TIndex const & index)
+{
+ for (CountryObservers const & observer : m_observers)
+ observer.m_changeCountryFn(index);
+}
- // new status for country, "Downloading"
- NotifyStatusChanged(cnt.GetIndex());
- }
- }
+void Storage::DownloadNextCountryFromQueue()
+{
+ if (m_queue.empty())
+ return;
- void Storage::DownloadNextFile(QueuedCountry const & cnt)
- {
- // send Country name for statistics
- m_downloader->GetServersList(cnt.GetFileName(),
- bind(&Storage::OnServerListDownloaded, this, _1));
- }
+ QueuedCountry & queuedCountry = m_queue.front();
+ DownloadNextFile(queuedCountry);
- /*
- m2::RectD Storage::CountryBounds(TIndex const & index) const
- {
- Country const & country = CountryByIndex(index);
- return country.Bounds();
- }
- */
+ // New status for the country, "Downloading"
+ NotifyStatusChanged(queuedCountry.GetIndex());
+}
- bool Storage::DeleteFromDownloader(TIndex const & index)
- {
- // 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);
- }
+void Storage::DownloadNextFile(QueuedCountry const & country)
+{
+ CountryFile const & countryFile = GetCountryFile(country.GetIndex());
- NotifyStatusChanged(index);
- return true;
- }
+ // send Country name for statistics
+ m_downloader->GetServersList(countryFile.GetNameWithoutExt(),
+ bind(&Storage::OnServerListDownloaded, this, _1));
+}
+bool Storage::DeleteFromDownloader(TIndex const & index)
+{
+ if (!DeleteCountryFilesFromDownloader(index, TMapOptions::EMapWithCarRouting))
return false;
- }
+ KickDownloaderAfterDeletionOfCountryFiles(index);
+ NotifyStatusChanged(index);
+ return true;
+}
+
+bool Storage::IsDownloadInProgress() const { return !m_queue.empty(); }
- bool Storage::IsDownloadInProgress() const
+void Storage::LoadCountriesFile(bool forceReload)
+{
+ if (forceReload)
+ m_countries.Clear();
+
+ if (m_countries.SiblingsCount() == 0)
{
- return !m_queue.empty();
+ 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::LoadCountriesFile(bool forceReload)
- {
- if (forceReload)
- m_countries.Clear();
+int Storage::Subscribe(TChangeCountryFunction const & change, TProgressFunction const & progress)
+{
+ CountryObservers obs;
- if (m_countries.SiblingsCount() == 0)
+ obs.m_changeCountryFn = change;
+ obs.m_progressFn = progress;
+ obs.m_slotId = ++m_currentSlotId;
+
+ m_observers.push_back(obs);
+
+ return obs.m_slotId;
+}
+
+void Storage::Unsubscribe(int slotId)
+{
+ for (auto i = m_observers.begin(); i != m_observers.end(); ++i)
+ {
+ if (i->m_slotId == slotId)
{
- 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));
+ m_observers.erase(i);
+ return;
}
}
+}
- int Storage::Subscribe(TChangeCountryFunction const & change,
- TProgressFunction const & progress)
- {
- CountryObservers obs;
+void Storage::OnMapFileDownloadFinished(bool success,
+ MapFilesDownloader::TProgress const & progress)
+{
+ if (m_queue.empty())
+ return;
- obs.m_changeCountryFn = change;
- obs.m_progressFn = progress;
- obs.m_slotId = ++m_currentSlotId;
+ QueuedCountry & queuedCountry = m_queue.front();
+ TIndex const index = queuedCountry.GetIndex();
- m_observers.push_back(obs);
+ Platform & platform = GetPlatform();
+ string const path = GetFileDownloadPath(index, queuedCountry.GetCurrentFile());
- return obs.m_slotId;
- }
+ success = success && platform.IsFileExistsByFullPath(path) &&
+ RegisterDownloadedFile(path, progress.first /* size */, GetCurrentDataVersion());
- void Storage::Unsubscribe(int slotId)
+ if (success && queuedCountry.SwitchToNextFile())
{
- for (auto i = m_observers.begin(); i != m_observers.end(); ++i)
- {
- if (i->m_slotId == slotId)
- {
- m_observers.erase(i);
- return;
- }
- }
+ DownloadNextFile(queuedCountry);
+ return;
}
- void Storage::OnMapDownloadFinished(bool success, MapFilesDownloader::TProgress const & progress)
{
- if (m_queue.empty())
+ string optionsName;
+ switch (queuedCountry.GetInitOptions())
{
- ASSERT ( false, ("queue can't be empty") );
- return;
- }
-
- QueuedCountry & cnt = m_queue.front();
- TIndex const index = cnt.GetIndex();
-
- 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}}));
+ case TMapOptions::ENothing:
+ optionsName = "Nothing";
+ break;
+ case TMapOptions::EMap:
+ optionsName = "Map";
+ break;
+ case TMapOptions::ECarRouting:
+ optionsName = "CarRouting";
+ break;
+ case TMapOptions::EMapWithCarRouting:
+ optionsName = "MapWithCarRouting";
+ break;
}
+ alohalytics::LogEvent(
+ "$OnMapDownloadFinished",
+ alohalytics::TStringMap({{"name", GetCountryFile(index).GetNameWithoutExt()},
+ {"status", success ? "ok" : "failed"},
+ {"version", strings::to_string(GetCurrentDataVersion())},
+ {"option", optionsName}}));
+ }
+ if (success)
+ {
+ shared_ptr<LocalCountryFile> localFile = GetLocalFile(index, GetCurrentDataVersion());
+ ASSERT(localFile.get(), ());
+ OnMapDownloadFinished(localFile);
+ }
+ else
+ {
+ OnMapDownloadFailed();
+ }
- if (downloadHasFailed)
- {
- // add to failed countries set
- m_failedCountries.insert(index);
- }
- else
- {
- ASSERT_EQUAL(progress.first, progress.second, ());
- ASSERT_EQUAL(progress.first, cnt.GetDownloadSize(), ());
+ m_queue.pop_front();
- m_countryProgress.first += progress.first;
- if (cnt.MoveNextFile())
- {
- DownloadNextFile(cnt);
- return;
- }
+ NotifyStatusChanged(index);
- // notify framework that downloading is done
- m_updateAfterDownload(cnt.GetMapFileName(), cnt.GetInitOptions());
- }
+ m_downloader->Reset();
+ DownloadNextCountryFromQueue();
+}
- m_queue.pop_front();
+void Storage::ReportProgress(TIndex const & idx, pair<int64_t, int64_t> const & p)
+{
+ for (CountryObservers const & o : m_observers)
+ o.m_progressFn(idx, p);
+}
- NotifyStatusChanged(index);
+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));
+}
- m_downloader->Reset();
- DownloadNextCountryFromQueue();
- }
+void Storage::OnMapFileDownloadProgress(MapFilesDownloader::TProgress const & progress)
+{
+ // Queue can be empty because countries were deleted from queue.
+ if (m_queue.empty())
+ return;
- void Storage::ReportProgress(TIndex const & idx, pair<int64_t, int64_t> const & p)
+ if (!m_observers.empty())
{
- for (CountryObservers const & o : m_observers)
- o.m_progressFn(idx, p);
+ 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);
}
+}
- void Storage::OnMapDownloadProgress(MapFilesDownloader::TProgress const & progress)
- {
- if (m_queue.empty())
- {
- ASSERT ( false, ("queue can't be empty") );
- return;
- }
+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);
- if (!m_observers.empty())
- {
- MapFilesDownloader::TProgress p = progress;
- p.first += m_countryProgress.first;
- p.second = m_countryProgress.second;
+ ASSERT_EQUAL(size, expectedSize, ("Downloaded file size mismatch:", size,
+ "bytes were downloaded,", expectedSize, "bytes expected."));
- ReportProgress(m_queue.front().GetIndex(), p);
- }
+ CountryFile const countryFile = GetCountryFile(index);
+ shared_ptr<LocalCountryFile> localFile = GetLocalFile(index, version);
+ if (localFile.get() == nullptr)
+ localFile = PreparePlaceForCountryFiles(countryFile, version);
+ if (localFile.get() == nullptr)
+ {
+ LOG(LERROR, ("Local file data structure can't prepared for downloaded file(", path, ")."));
+ return false;
}
+ if (!my::RenameFileX(path, localFile->GetPath(queuedCountry.GetCurrentFile())))
+ return false;
+ RegisterCountryFiles(localFile);
+ return true;
+}
- void Storage::OnServerListDownloaded(vector<string> const & urls)
- {
- if (m_queue.empty())
- {
- ASSERT ( false, ("queue can't be empty") );
- return;
- }
+void Storage::OnMapDownloadFinished(shared_ptr<LocalCountryFile> localFile)
+{
+ DeleteCountryIndexes(localFile->GetCountryFile());
- QueuedCountry const & cnt = m_queue.front();
+ // Notify framework that all requested files for the country were downloaded.
+ m_updateAfterDownload(*localFile);
+}
- 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);
+void Storage::OnMapDownloadFailed()
+{
+ TIndex const & index = m_queue.front().GetIndex();
- 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));
- }
+ // Add country to the failed countries set.
+ m_failedCountries.insert(index);
+ m_downloader->Reset();
+ DownloadNextCountryFromQueue();
+}
- string Storage::GetFileDownloadUrl(string const & baseUrl, string const & fName) const
- {
- return baseUrl + OMIM_OS_NAME "/" + strings::to_string(m_currentVersion) + "/" + UrlEncode(fName);
- }
+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));
+}
- namespace
- {
- class EqualFileName
- {
- string const & m_name;
- public:
- explicit EqualFileName(string const & name) : m_name(name) {}
- bool operator()(SimpleTree<Country> const & node) const
- {
- Country const & c = node.Value();
- if (c.GetFilesCount() > 0)
- return (c.GetFile().GetFileWithoutExt() == m_name);
- else
- return false;
- }
- };
- }
+TIndex Storage::FindIndexByFile(string const & name) const
+{
+ EqualFileName fn(name);
- TIndex Storage::FindIndexByFile(string const & name) const
+ for (size_t i = 0; i < m_countries.SiblingsCount(); ++i)
{
- EqualFileName fn(name);
+ if (fn(m_countries[i]))
+ return TIndex(static_cast<int>(i));
- for (size_t i = 0; i < m_countries.SiblingsCount(); ++i)
+ for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j)
{
- if (fn(m_countries[i]))
- return TIndex(static_cast<int>(i));
+ if (fn(m_countries[i][j]))
+ return TIndex(static_cast<int>(i), static_cast<int>(j));
- for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j)
+ for (size_t k = 0; k < m_countries[i][j].SiblingsCount(); ++k)
{
- 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));
- }
+ if (fn(m_countries[i][j][k]))
+ return TIndex(static_cast<int>(i), static_cast<int>(j), static_cast<int>(k));
}
}
-
- return TIndex();
}
- vector<TIndex> Storage::FindAllIndexesByFile(string const & name) const
+ return TIndex();
+}
+
+vector<TIndex> Storage::FindAllIndexesByFile(string const & name) const
+{
+ EqualFileName fn(name);
+ vector<TIndex> res;
+
+ for (size_t i = 0; i < m_countries.SiblingsCount(); ++i)
{
- EqualFileName fn(name);
- vector<TIndex> res;
+ if (fn(m_countries[i]))
+ res.emplace_back(static_cast<int>(i));
- for (size_t i = 0; i < m_countries.SiblingsCount(); ++i)
+ for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j)
{
- if (fn(m_countries[i]))
- res.emplace_back(static_cast<int>(i));
+ if (fn(m_countries[i][j]))
+ res.emplace_back(static_cast<int>(i), static_cast<int>(j));
- for (size_t j = 0; j < m_countries[i].SiblingsCount(); ++j)
+ for (size_t k = 0; k < m_countries[i][j].SiblingsCount(); ++k)
{
- 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));
- }
+ if (fn(m_countries[i][j][k]))
+ res.emplace_back(static_cast<int>(i), static_cast<int>(j), static_cast<int>(k));
}
}
-
- return res;
}
- void Storage::GetOutdatedCountries(vector<Country const *> & res) const
+ return res;
+}
+
+void Storage::GetOutdatedCountries(vector<Country const *> & countries) const
+{
+ for (auto const & p : m_localFiles)
{
- Platform & pl = GetPlatform();
- Platform::FilesList fList;
- pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, fList);
+ 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)
+ {
+ countries.push_back(&CountryByIndex(index));
+ }
+ }
+}
- for_each(fList.begin(), fList.end(), bind(&my::GetNameWithoutExt, _1));
+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;
+}
- fList.erase(remove_if(fList.begin(), fList.end(), [] (string const & t)
- {
- return (t == WORLD_COASTS_FILE_NAME) || (t == WORLD_FILE_NAME);
- }), fList.end());
+TStatus Storage::CountryStatusFull(TIndex const & index, TStatus const status) const
+{
+ if (status != TStatus::EUnknown)
+ return status;
- fList.erase(remove_if(fList.begin(), fList.end(), [this] (string const & file)
- {
- return (CountryStatusEx(FindIndexByFile(file)) != TStatus::EOnDiskOutOfDate);
- }), fList.end());
+ shared_ptr<LocalCountryFile> localFile = GetLatestLocalFile(index);
+ if (localFile.get() == nullptr || !localFile->OnDisk(TMapOptions::EMap))
+ return TStatus::ENotDownloaded;
- for (size_t i = 0; i < fList.size(); ++i)
- res.push_back(&CountryByIndex(FindIndexByFile(fList[i])));
- }
+ CountryFile const & countryFile = GetCountryFile(index);
+ if (GetRemoteSize(countryFile, TMapOptions::EMap) == 0)
+ return TStatus::EUnknown;
- void Storage::SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader)
- {
- m_downloader = move(downloader);
- }
+ if (localFile->GetVersion() != GetCurrentDataVersion())
+ return TStatus::EOnDiskOutOfDate;
+ return TStatus::EOnDisk;
+}
- TStatus Storage::CountryStatusWithoutFailed(TIndex const & index) const
+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);
+
+ shared_ptr<LocalCountryFile> localCountryFile = GetLatestLocalFile(index);
+ for (TMapOptions file : {TMapOptions::EMap, TMapOptions::ECarRouting})
{
- // 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())
+ // Check whether requested files are on disk and up-to-date.
+ if (HasOptions(opt, file) && localCountryFile.get() && localCountryFile->OnDisk(file) &&
+ localCountryFile->GetVersion() == GetCurrentDataVersion())
{
- if (found == m_queue.begin())
- return TStatus::EDownloading;
- else
- return TStatus::EInQueue;
+ opt = UnsetOptions(opt, file);
}
-
- return CountryStatusFull(index, TStatus::EUnknown);
}
+ 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;
+}
+
+QueuedCountry * Storage::FindCountryInQueue(TIndex const & index)
+{
+ auto it = find(m_queue.begin(), m_queue.end(), index);
+ return it == m_queue.end() ? nullptr : &*it;
+}
+
+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;
+}
+
+bool Storage::IsCountryInQueue(TIndex const & index) const
+{
+ return FindCountryInQueue(index) != nullptr;
+}
+
+bool Storage::IsCountryFirstInQueue(TIndex const & index) const
+{
+ return !m_queue.empty() && m_queue.front().GetIndex() == index;
+}
- TStatus Storage::CountryStatusFull(TIndex const & index, TStatus const status) const
+void Storage::SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader)
+{
+ m_downloader = move(downloader);
+}
+
+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 (status != TStatus::EUnknown)
- return status;
+ if (file->GetVersion() == version)
+ return file;
+ }
+ return shared_ptr<LocalCountryFile>();
+}
- TStatus res = status;
- Country const & c = CountryByIndex(index);
- LocalAndRemoteSizeT const size = c.Size(TMapOptions::EMap);
+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);
+}
- if (size.first == 0)
- return TStatus::ENotDownloaded;
+void Storage::RegisterCountryFiles(TIndex const & index, string const & directory, int64_t version)
+{
+ shared_ptr<LocalCountryFile> localFile = GetLocalFile(index, version);
+ if (localFile)
+ return;
- if (size.second == 0)
- return TStatus::EUnknown;
+ CountryFile const & countryFile = GetCountryFile(index);
+ localFile = make_shared<LocalCountryFile>(directory, countryFile, version);
+ RegisterCountryFiles(localFile);
+}
- res = TStatus::EOnDisk;
- if (size.first != size.second)
- {
- /// @todo Do better version check, not just size comparison.
+void Storage::RegisterFakeCountryFiles(platform::LocalCountryFile const & localFile)
+{
+ shared_ptr<LocalCountryFile> fakeCountryLocalFile = make_shared<LocalCountryFile>(localFile);
+ fakeCountryLocalFile->SyncWithDisk();
+ m_localFilesForFakeCountries[fakeCountryLocalFile->GetCountryFile()] = fakeCountryLocalFile;
+}
- // 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;
+void Storage::DeleteCountryFiles(TIndex const & index, TMapOptions opt)
+{
+ auto const it = m_localFiles.find(index);
+ if (it == m_localFiles.end())
+ return;
- uint64_t sz = 0;
- if (!pl.GetFileSizeByFullPath(pl.WritablePathForFile(fName), sz) || sz != size.second)
- res = TStatus::EOnDiskOutOfDate;
- }
+ // TODO (@gorshenin): map-only indexes should not be touched when
+ // routing indexes are removed.
+ if (!it->second.empty())
+ DeleteCountryIndexes(it->second.front()->GetCountryFile());
- return res;
+ list<shared_ptr<platform::LocalCountryFile>> & localFiles = it->second;
+ for (shared_ptr<LocalCountryFile> & localFile : localFiles)
+ {
+ localFile->DeleteFromDisk(opt);
+ localFile->SyncWithDisk();
+ if (localFile->GetFiles() == TMapOptions::ENothing)
+ localFile.reset();
+ }
+ 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))
+ {
+ // Abrupt downloading of the current file if it should be removed.
+ if (HasOptions(opt, queuedCountry->GetCurrentFile()))
+ m_downloader->Reset();
}
+ 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;
+}
+
+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();
+}
+
+uint64_t Storage::GetDownloadSize(QueuedCountry const & queuedCountry) const
+{
+ CountryFile const & file = GetCountryFile(queuedCountry.GetIndex());
+ return GetRemoteSize(file, queuedCountry.GetCurrentFile());
+}
+
+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);
}
+} // namespace storage
diff --git a/storage/storage.hpp b/storage/storage.hpp
index efdc07f4c6..0e3b1f1ccb 100644
--- a/storage/storage.hpp
+++ b/storage/storage.hpp
@@ -3,168 +3,230 @@
#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/vector.hpp"
+#include "std/function.hpp"
#include "std/list.hpp"
-#include "std/string.hpp"
#include "std/set.hpp"
-#include "std/function.hpp"
+#include "std/shared_ptr.hpp"
+#include "std/string.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
+/// 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
{
- /// We support only one simultaneous request at the moment
- unique_ptr<MapFilesDownloader> m_downloader;
+ TChangeCountryFunction m_changeCountryFn;
+ TProgressFunction m_progressFn;
+ int m_slotId;
+ };
- /// stores timestamp for update checks
- int64_t m_currentVersion;
+ typedef list<CountryObservers> ObserversContT;
+ ObserversContT m_observers;
+ //@}
- CountriesContainerT m_countries;
+ typedef function<void(platform::LocalCountryFile const &)> TUpdateAfterDownload;
- /// store queue for downloading
- class QueuedCountry
- {
- TIndex m_index;
- CountryFile const * m_pFile;
- TMapOptions m_init, m_left, m_current;
+ // This function is called each time all files requested for a
+ // country were successfully downloaded.
+ TUpdateAfterDownload m_updateAfterDownload;
- public:
- QueuedCountry(Storage const & storage, TIndex const & index, TMapOptions opt);
+ void DownloadNextCountryFromQueue();
- void AddOptions(TMapOptions opt);
- bool MoveNextFile();
- bool Correct(TStatus currentStatus);
+ void LoadCountriesFile(bool forceReload);
- 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;
- };
+ void ReportProgress(TIndex const & index, pair<int64_t, int64_t> const & p);
- 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;
+ /// Called on the main thread by MapFilesDownloader when list of
+ /// suitable servers is received.
+ void OnServerListDownloaded(vector<string> const & urls);
- /// stores countries which download has failed recently
- typedef set<TIndex> TCountriesSet;
- TCountriesSet m_failedCountries;
+ /// Called on the main thread by MapFilesDownloader when
+ /// downloading of a map file succeeds/fails.
+ void OnMapFileDownloadFinished(bool success, MapFilesDownloader::TProgress const & progress);
- /// used to correctly calculate total country download progress with more than 1 file
- /// <current, total>
- MapFilesDownloader::TProgress m_countryProgress;
+ /// Periodically called on the main thread by MapFilesDownloader
+ /// during the downloading process.
+ void OnMapFileDownloadProgress(MapFilesDownloader::TProgress const & progress);
- /// @name Communicate with GUI
- //@{
- typedef function<void (TIndex const &)> TChangeCountryFunction;
- typedef function<void (TIndex const &, LocalAndRemoteSizeT const &)> TProgressFunction;
+ bool RegisterDownloadedFile(string const & path, uint64_t size, int64_t version);
+ void OnMapDownloadFinished(shared_ptr<platform::LocalCountryFile> localFile);
+ void OnMapDownloadFailed();
- int m_currentSlotId;
+ /// Initiates downloading of the next file from the queue.
+ void DownloadNextFile(QueuedCountry const & country);
- struct CountryObservers
- {
- TChangeCountryFunction m_changeCountryFn;
- TProgressFunction m_progressFn;
- int m_slotId;
- };
+public:
+ Storage();
- typedef list<CountryObservers> ObserversContT;
- ObserversContT m_observers;
- //@}
+ void Init(TUpdateAfterDownload const & updateFn);
- /// @name Communicate with Framework
- //@{
- typedef function<void (string const &, TMapOptions)> TUpdateAfterDownload;
- TUpdateAfterDownload m_updateAfterDownload;
- //@}
+ // 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();
- void DownloadNextCountryFromQueue();
+ // Returns list of all local maps, including fake countries.
+ void GetLocalMaps(vector<platform::CountryFile> & maps);
- void LoadCountriesFile(bool forceReload);
+ /// @return unique identifier that should be used with Unsubscribe function
+ int Subscribe(TChangeCountryFunction const & change, TProgressFunction const & progress);
+ void Unsubscribe(int slotId);
- void ReportProgress(TIndex const & index, pair<int64_t, int64_t> const & p);
+ 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;
- /// Called on the main thread by MapFilesDownloader when list of
- /// suitable servers is received.
- void OnServerListDownloaded(vector<string> const & urls);
+ size_t CountriesCount(TIndex const & index) const;
+ string const & CountryName(TIndex const & index) const;
+ string const & CountryFlag(TIndex const & index) const;
- /// Called on the main thread by MapFilesDownloader when
- /// downloading of a map file succeeds/fails.
- void OnMapDownloadFinished(bool success, MapFilesDownloader::TProgress const & progress);
+ 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;
- /// Periodically called on the main thread by MapFilesDownloader
- /// during the downloading process.
- void OnMapDownloadProgress(MapFilesDownloader::TProgress const & progress);
+ /// 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;
- /// Initiates downloading of the next file from the queue.
- void DownloadNextFile(QueuedCountry const & cnt);
+ /// 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);
- public:
- Storage();
+ /// Removes country files (for all versions) from the device.
+ /// Notifies observers about country status change.
+ void DeleteCountry(TIndex const & index, TMapOptions opt);
- void Init(TUpdateAfterDownload const & updateFn);
+ /// Removes country files of a particular version from the device.
+ /// Notifies observers about country status change.
+ void DeleteCustomCountryVersion(platform::LocalCountryFile const & localFile);
- /// @return unique identifier that should be used with Unsubscribe function
- int Subscribe(TChangeCountryFunction const & change,
- TProgressFunction const & progress);
- void Unsubscribe(int slotId);
+ /// \return True iff country denoted by index was successfully
+ /// deleted from the downloader's queue.
+ bool DeleteFromDownloader(TIndex const & index);
+ bool IsDownloadInProgress() const;
- 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 NotifyStatusChanged(TIndex const & index);
- size_t CountriesCount(TIndex const & index) const;
- string const & CountryName(TIndex const & index) const;
- string const & CountryFlag(TIndex const & index) const;
+ string GetFileDownloadUrl(string const & baseUrl, TIndex const & index, TMapOptions file) 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;
+ /// @param[out] res Populated with oudated countries.
+ void GetOutdatedCountries(vector<Country const *> & countries) 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;
+ inline int64_t GetCurrentDataVersion() const { return m_currentVersion; }
- //m2::RectD CountryBounds(TIndex const & index) const;
+ void SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader);
- void DownloadCountry(TIndex const & index, TMapOptions opt);
- bool DeleteFromDownloader(TIndex const & index);
- bool IsDownloadInProgress() const;
+private:
+ TStatus CountryStatusWithoutFailed(TIndex const & index) const;
+ TStatus CountryStatusFull(TIndex const & index, TStatus const status) const;
- void NotifyStatusChanged(TIndex const & index);
+ // 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;
- string GetFileDownloadUrl(string const & baseUrl, string const & fName) 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;
- /// @param[out] res Populated with oudated countries.
- void GetOutdatedCountries(vector<Country const *> & res) const;
+ // Returns a pointer to a country in the downloader's queue.
+ QueuedCountry * FindCountryInQueue(TIndex const & index);
- int64_t GetCurrentDataVersion() const { return m_currentVersion; }
+ // Returns a pointer to a country in the downloader's queue.
+ QueuedCountry const * FindCountryInQueue(TIndex const & index) const;
- void SetDownloaderForTesting(unique_ptr<MapFilesDownloader> && downloader);
+ // Returns true when country is in the downloader's queue.
+ bool IsCountryInQueue(TIndex const & index) const;
- private:
- TStatus CountryStatusWithoutFailed(TIndex const & index) const;
- TStatus CountryStatusFull(TIndex const & index, TStatus const status) const;
- };
-}
+ // Returns true when country is first in the downloader's queue.
+ bool IsCountryFirstInQueue(TIndex const & index) 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;
+
+ // 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);
+
+ // 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
diff --git a/storage/storage.pro b/storage/storage.pro
index ba4d116a3e..5cd9da9f8a 100644
--- a/storage/storage.pro
+++ b/storage/storage.pro
@@ -18,6 +18,7 @@ HEADERS += \
http_map_files_downloader.hpp \
index.hpp \
map_files_downloader.hpp \
+ queued_country.hpp \
simple_tree.hpp \
storage.hpp \
storage_defines.hpp \
@@ -28,5 +29,6 @@ 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 5aa9df921b..901ecc10d0 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 ae544db595..cb69bcb2fa 100644
--- a/storage/storage_tests/fake_map_files_downloader.hpp
+++ b/storage/storage_tests/fake_map_files_downloader.hpp
@@ -18,6 +18,7 @@ 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
new file mode 100644
index 0000000000..01634a6bcf
--- /dev/null
+++ b/storage/storage_tests/queued_country_tests.cpp
@@ -0,0 +1,106 @@
+#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 60d795d4c7..9bc206024c 100644
--- a/storage/storage_tests/storage_tests.cpp
+++ b/storage/storage_tests/storage_tests.cpp
@@ -5,6 +5,9 @@
#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"
@@ -14,67 +17,73 @@
#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, string const & countryFileName, TMapOptions files)
+ CountryDownloaderChecker(Storage & storage, TIndex const & index, TMapOptions files,
+ vector<TStatus> const & transitionList)
: m_storage(storage),
- m_index(m_storage.FindIndexByFile(countryFileName)),
+ m_index(index),
+ m_countryFile(storage.GetCountryFile(m_index)),
m_files(files),
- m_lastStatus(TStatus::ENotDownloaded),
m_bytesDownloaded(0),
m_totalBytesToDownload(0),
- m_slot(0)
+ m_slot(0),
+ m_currStatus(0),
+ m_transitionList(transitionList)
{
m_slot = m_storage.Subscribe(
bind(&CountryDownloaderChecker::OnCountryStatusChanged, this, _1),
bind(&CountryDownloaderChecker::OnCountryDownloadingProgress, this, _1, _2));
- CHECK(m_index.IsValid(), ());
+ TEST(m_index.IsValid(), (m_countryFile));
+ TEST(!m_transitionList.empty(), (m_countryFile));
}
void StartDownload()
{
- CHECK_EQUAL(m_lastStatus, m_storage.CountryStatusEx(m_index), ());
+ 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));
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);
- CheckStatusTransition(m_lastStatus, status);
- if (status == TStatus::EDownloading)
+ 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)
{
LocalAndRemoteSizeT localAndRemoteSize = m_storage.CountrySizeInBytes(m_index, m_files);
m_totalBytesToDownload = localAndRemoteSize.second;
}
- m_lastStatus = status;
}
void OnCountryDownloadingProgress(TIndex const & index, LocalAndRemoteSizeT const & progress)
@@ -82,185 +91,410 @@ private:
if (index != m_index)
return;
- CHECK_GREATER(progress.first, m_bytesDownloaded, ());
+ LOG(LINFO, (m_countryFile, "downloading progress:", progress));
+
+ TEST_GREATER(progress.first, m_bytesDownloaded, (m_countryFile));
m_bytesDownloaded = progress.first;
- CHECK_LESS_OR_EQUAL(m_bytesDownloaded, m_totalBytesToDownload, ());
+ TEST_LESS_OR_EQUAL(m_bytesDownloaded, m_totalBytesToDownload, (m_countryFile));
LocalAndRemoteSizeT localAndRemoteSize = m_storage.CountrySizeInBytes(m_index, m_files);
- CHECK_EQUAL(m_totalBytesToDownload, localAndRemoteSize.second, ());
+ TEST_EQUAL(m_totalBytesToDownload, localAndRemoteSize.second, (m_countryFile));
}
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.
-class AbsentCountryDownloaderChecker : public CountryDownloaderChecker
+unique_ptr<CountryDownloaderChecker> AbsentCountryDownloaderChecker(Storage & storage,
+ TIndex const & index,
+ TMapOptions files)
{
-public:
- AbsentCountryDownloaderChecker(Storage & storage, string const & countryFileName,
- TMapOptions files)
- : CountryDownloaderChecker(storage, countryFileName, 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});
+}
- ~AbsentCountryDownloaderChecker() override = default;
+// Checks following state transitions:
+// NotDownloaded -> Downloading -> NotDownloaded.
+unique_ptr<CountryDownloaderChecker> CancelledCountryDownloaderChecker(Storage & storage,
+ TIndex const & index,
+ TMapOptions files)
+{
+ return make_unique<CountryDownloaderChecker>(
+ storage, index, files,
+ vector<TStatus>{TStatus::ENotDownloaded, TStatus::EDownloading, TStatus::ENotDownloaded});
+}
-protected:
- void CheckStatusTransition(TStatus oldStatus, TStatus newStatus) const override
+void OnCountryDownloaded(LocalCountryFile const & localFile)
+{
+ LOG(LINFO, ("OnCountryDownloaded:", localFile));
+}
+
+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, ")"));
{
- 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));
- }
+ string const zeroes(size, '\0');
+ FileWriter writer(localFile->GetPath(TMapOptions::EMap));
+ writer.Write(zeroes.data(), zeroes.size());
}
-};
+ localFile->SyncWithDisk();
+ TEST_EQUAL(TMapOptions::EMap, localFile->GetFiles(), ());
+ TEST_EQUAL(size, localFile->GetSize(TMapOptions::EMap), ());
+ return localFile;
+}
-// Checks following state transitions:
-// NotDownloaded -> InQueue -> Downloading -> OnDisk.
-class QueuedCountryDownloaderChecker : public CountryDownloaderChecker
+class CountryStatusChecker
{
public:
- QueuedCountryDownloaderChecker(Storage & storage, string const & countryFileName,
- TMapOptions files)
- : CountryDownloaderChecker(storage, countryFileName, files)
+ CountryStatusChecker(Storage & storage, TIndex const & index, TStatus status)
+ : m_storage(storage), m_index(index), m_status(status), m_triggered(false)
{
+ m_slot = m_storage.Subscribe(
+ bind(&CountryStatusChecker::OnCountryStatusChanged, this, _1),
+ bind(&CountryStatusChecker::OnCountryDownloadingProgress, this, _1, _2));
}
- ~QueuedCountryDownloaderChecker() override = default;
+ ~CountryStatusChecker()
+ {
+ TEST(m_triggered, ("Status checker wasn't triggered."));
+ m_storage.Unsubscribe(m_slot);
+ }
-protected:
- void CheckStatusTransition(TStatus oldStatus, TStatus newStatus) const override
+private:
+ void OnCountryStatusChanged(TIndex const & index)
{
- 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));
- }
+ 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."));
+ }
+
+ Storage & m_storage;
+ TIndex const & m_index;
+ TStatus m_status;
+ bool m_triggered;
+ int m_slot;
};
-// Removes country's files that can be created during and after downloading.
-void CleanupCountryFiles(string const & countryFileName)
+void InitStorage(Storage & storage, TaskRunner & runner)
{
- Platform & platform = GetPlatform();
+ storage.Init(&OnCountryDownloaded);
+ storage.RegisterAllLocalMaps();
+ storage.SetDownloaderForTesting(make_unique<FakeMapFilesDownloader>(runner));
+}
+} // namespace
- string const localMapFile =
- my::JoinFoldersToPath(platform.WritableDir(), countryFileName + DATA_FILE_EXTENSION);
- my::DeleteFileX(localMapFile);
- my::DeleteFileX(localMapFile + READY_FILE_EXTENSION);
+UNIT_TEST(StorageTest_Smoke)
+{
+ Storage storage;
- string const localRoutingFile = localMapFile + ROUTING_FILE_EXTENSION;
- my::DeleteFileX(localRoutingFile);
- my::DeleteFileX(localRoutingFile + 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, ());
}
-void OnCountryDownloaded(string const & mapFileName, TMapOptions files)
+UNIT_TEST(StorageTest_SingleCountryDownloading)
{
- Platform & platform = GetPlatform();
+ Storage storage;
+ TaskRunner runner;
+ InitStorage(storage, runner);
- string const localMapFile = my::JoinFoldersToPath(platform.WritableDir(), mapFileName);
- string const localRoutingFile = localMapFile + ROUTING_FILE_EXTENSION;
+ TIndex const azerbaijanIndex = storage.FindIndexByFile("Azerbaijan");
+ TEST(azerbaijanIndex.IsValid(), ());
- 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), ());
+ 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();
+ }
}
-} // namespace
+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_Smoke)
+UNIT_TEST(StorageTest_DeleteTwoVersionsOfTheSameCountry)
{
- Storage st;
+ 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), ());
+}
+
+UNIT_TEST(StorageTest_DownloadCountryAndDeleteRoutingOnly)
+{
+ Storage storage;
+ TaskRunner runner;
+ InitStorage(storage, runner);
- TIndex const i1 = st.FindIndexByFile("USA_Georgia");
- TEST(i1.IsValid(), ());
- TEST_EQUAL(st.CountryFileName(i1, TMapOptions::EMap), "USA_Georgia" DATA_FILE_EXTENSION, ());
+ TIndex const index = storage.FindIndexByFile("Azerbaijan");
+ TEST(index.IsValid(), ());
+ storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting);
- TIndex const i2 = st.FindIndexByFile("Georgia");
- TEST(i2.IsValid(), ());
- TEST_EQUAL(st.CountryFileName(i2, TMapOptions::ECarRouting),
- "Georgia" DATA_FILE_EXTENSION ROUTING_FILE_EXTENSION, ());
+ {
+ unique_ptr<CountryDownloaderChecker> checker =
+ AbsentCountryDownloaderChecker(storage, index, TMapOptions::EMapWithCarRouting);
+ checker->StartDownload();
+ runner.Run();
+ }
+
+ // 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(), ());
+
+ 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(), ());
- TEST_NOT_EQUAL(i1, i2, ());
+ storage.DeleteCountry(index, TMapOptions::EMap);
+ shared_ptr<LocalCountryFile> localFileC = storage.GetLatestLocalFile(index);
+ TEST(!localFileC.get(), (*localFileC));
}
-UNIT_TEST(StorageTest_SingleCountryDownloading)
+UNIT_TEST(StorageTest_DownloadMapAndRoutingSeparately)
{
- string const azerbaijanFileName = "Azerbaijan";
- CleanupCountryFiles(azerbaijanFileName);
-
Storage storage;
- storage.Init(&OnCountryDownloaded);
+ TaskRunner runner;
+ InitStorage(storage, runner);
- TaskRunner taskRunner;
- storage.SetDownloaderForTesting(make_unique<FakeMapFilesDownloader>(taskRunner));
+ TIndex const index = storage.FindIndexByFile("Azerbaijan");
+ TEST(index.IsValid(), ());
+ storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting);
+ // Download map file only.
{
- MY_SCOPE_GUARD(cleanupCountryFiles, bind(&CleanupCountryFiles, azerbaijanFileName));
- AbsentCountryDownloaderChecker checker(storage, azerbaijanFileName, TMapOptions::EMap);
- checker.StartDownload();
- taskRunner.Run();
+ 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.
{
- MY_SCOPE_GUARD(cleanupCountryFiles, bind(&CleanupCountryFiles, azerbaijanFileName));
- AbsentCountryDownloaderChecker checker(storage, azerbaijanFileName,
- TMapOptions::EMapWithCarRouting);
- checker.StartDownload();
- taskRunner.Run();
+ unique_ptr<CountryDownloaderChecker> checker =
+ PresentCountryDownloaderChecker(storage, index, TMapOptions::ECarRouting);
+ checker->StartDownload();
+ runner.Run();
+ }
+
+ shared_ptr<LocalCountryFile> localFileB = storage.GetLatestLocalFile(index);
+ TEST(localFileB.get(), ());
+ TEST_EQUAL(localFileA.get(), localFileB.get(), (*localFileA, *localFileB));
+ TEST_EQUAL(TMapOptions::EMapWithCarRouting, localFileB->GetFiles(), ());
+
+ // Delete routing file and check status update.
+ {
+ CountryStatusChecker checker(storage, index, TStatus::EOnDisk);
+ storage.DeleteCountry(index, TMapOptions::ECarRouting);
+ }
+ 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);
}
}
-UNIT_TEST(StorageTest_TwoCountriesDownloading)
+UNIT_TEST(StorageTest_DeletePendingCountry)
{
- string const uruguayFileName = "Uruguay";
- string const venezuelaFileName = "Venezuela";
- CleanupCountryFiles(uruguayFileName);
- MY_SCOPE_GUARD(cleanupUruguayFiles, bind(&CleanupCountryFiles, uruguayFileName));
+ Storage storage;
+ TaskRunner runner;
+ InitStorage(storage, runner);
+
+ TIndex const index = storage.FindIndexByFile("Azerbaijan");
+ TEST(index.IsValid(), ());
+ storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting);
- CleanupCountryFiles(venezuelaFileName);
- MY_SCOPE_GUARD(cleanupVenezuelaFiles, bind(&CleanupCountryFiles, venezuelaFileName));
+ {
+ unique_ptr<CountryDownloaderChecker> checker =
+ CancelledCountryDownloaderChecker(storage, index, TMapOptions::EMap);
+ checker->StartDownload();
+ storage.DeleteCountry(index, TMapOptions::EMapWithCarRouting);
+ runner.Run();
+ }
+}
+UNIT_TEST(StorageTest_DownloadTwoCountriesAndDelete)
+{
Storage storage;
- storage.Init(&OnCountryDownloaded);
+ 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));
- TaskRunner taskRunner;
- storage.SetDownloaderForTesting(make_unique<FakeMapFilesDownloader>(taskRunner));
+ 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));
+
+ {
+ // 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));
- AbsentCountryDownloaderChecker uruguayChecker(storage, uruguayFileName, TMapOptions::EMap);
- QueuedCountryDownloaderChecker venezuelaChecker(storage, venezuelaFileName,
- TMapOptions::EMapWithCarRouting);
- uruguayChecker.StartDownload();
- venezuelaChecker.StartDownload();
- taskRunner.Run();
+ shared_ptr<LocalCountryFile> venezuelaFile = storage.GetLatestLocalFile(venezuelaIndex);
+ TEST(venezuelaFile.get(), ());
+ TEST_EQUAL(TMapOptions::EMap, venezuelaFile->GetFiles(), ());
}
diff --git a/storage/storage_tests/storage_tests.pro b/storage/storage_tests/storage_tests.pro
index 86879502d5..1f59397d0d 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 \