diff --git a/base/macros.hpp b/base/macros.hpp index 858b547c58..d53b0d89a0 100644 --- a/base/macros.hpp +++ b/base/macros.hpp @@ -14,10 +14,10 @@ namespace my #define ARRAY_SIZE(X) sizeof(::my::impl::ArraySize(X)) // Make class noncopyable. -#define NONCOPYABLE(class_name) \ -private: \ - class_name const & operator = (class_name const &); \ - class_name(class_name const &); +#define NONCOPYABLE(class_name) \ +private: \ + class_name const & operator=(class_name const &) = delete; \ + class_name(class_name const &) = delete ///////////////////////////////////////////////////////////// #define TO_STRING_IMPL(x) #x @@ -72,3 +72,9 @@ private: \ className(className &&) = delete; \ className & operator=(const className &) = delete; \ className & operator=(className &&) = delete; + +#if defined(__GNUC__) +#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define WARN_UNUSED_RESULT +#endif // defined(__GNUC__) diff --git a/base/timer.cpp b/base/timer.cpp index 8ff524bca3..51568af311 100644 --- a/base/timer.cpp +++ b/base/timer.cpp @@ -60,11 +60,15 @@ string FormatCurrentTime() return s; } +uint32_t GenerateTimestamp(int year, int month, int day) { + return (year - 100) * 10000 + (month + 1) * 100 + day; +} + uint32_t TodayAsYYMMDD() { time_t rawTime = time(NULL); tm * pTm = gmtime(&rawTime); - return (pTm->tm_year - 100) * 10000 + (pTm->tm_mon + 1) * 100 + pTm->tm_mday; + return GenerateTimestamp(pTm->tm_year, pTm->tm_mon, pTm->tm_mday); } namespace diff --git a/base/timer.hpp b/base/timer.hpp index cc6d0c4a12..6e8be8c4f8 100644 --- a/base/timer.hpp +++ b/base/timer.hpp @@ -25,6 +25,14 @@ public: }; string FormatCurrentTime(); + +/// Generates timestamp for a specified day. +/// \param year The number of years since 1900. +/// \param month The number of month since January, in the range 0 to 11. +/// \param day The day of the month, in the range 1 to 31. +/// \return Timestamp. +uint32_t GenerateTimestamp(int year, int month, int day); + uint32_t TodayAsYYMMDD(); /// Always creates strings in UTC time: 1997-07-16T07:30:15Z diff --git a/drape_head/drape_surface.cpp b/drape_head/drape_surface.cpp index e1286e27cf..8a41da185b 100644 --- a/drape_head/drape_surface.cpp +++ b/drape_head/drape_surface.cpp @@ -32,8 +32,7 @@ DrapeSurface::DrapeSurface() Platform & pl = GetPlatform(); pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps); - feature::DataHeader::Version version; - for_each(maps.begin(), maps.end(), bind(&model::FeaturesFetcher::RegisterMap, &m_model, _1, version)); + for_each(maps.begin(), maps.end(), bind(&model::FeaturesFetcher::RegisterMap, &m_model, _1)); ///} /// m_navigator.LoadState(); diff --git a/generator/feature_sorter.cpp b/generator/feature_sorter.cpp index 804fae1416..b9c8db2677 100644 --- a/generator/feature_sorter.cpp +++ b/generator/feature_sorter.cpp @@ -118,7 +118,7 @@ namespace feature // write version information { FileWriter w = m_writer.GetWriter(VERSION_FILE_TAG); - ver::WriteVersion(w); + version::WriteVersion(w); } // write own mwm header diff --git a/generator/generator_tests/check_mwms.cpp b/generator/generator_tests/check_mwms.cpp index cc97cf4c21..b139cddd49 100644 --- a/generator/generator_tests/check_mwms.cpp +++ b/generator/generator_tests/check_mwms.cpp @@ -24,8 +24,9 @@ UNIT_TEST(CheckMWM_LoadAll) { try { - feature::DataHeader::Version version; - m.RegisterMap(s, version); + pair p = m.RegisterMap(s); + TEST(p.first.IsLocked(), ()); + TEST(p.second, ()); } catch (RootException const & ex) { diff --git a/indexer/data_factory.cpp b/indexer/data_factory.cpp index b1acc286cf..fea7019966 100644 --- a/indexer/data_factory.cpp +++ b/indexer/data_factory.cpp @@ -10,20 +10,21 @@ #include "../coding/file_reader.hpp" #include "../coding/file_container.hpp" +namespace { -typedef feature::DataHeader FHeaderT; +using FHeaderT = feature::DataHeader; + +} // namespace void LoadMapHeader(FilesContainerR const & cont, FHeaderT & header) { ModelReaderPtr headerReader = cont.GetReader(HEADER_FILE_TAG); + version::MwmVersion version; - if (!cont.IsExist(VERSION_FILE_TAG)) - header.LoadVer1(headerReader); + if (version::ReadVersion(cont, version)) + header.Load(headerReader, version.format); else - { - ModelReaderPtr verReader = cont.GetReader(VERSION_FILE_TAG); - header.Load(headerReader, static_cast(ver::ReadVersion(verReader))); - } + header.LoadV1(headerReader); } void LoadMapHeader(ModelReaderPtr const & reader, FHeaderT & header) @@ -33,23 +34,13 @@ void LoadMapHeader(ModelReaderPtr const & reader, FHeaderT & header) void IndexFactory::Load(FilesContainerR const & cont) { + ReadVersion(cont, m_version); LoadMapHeader(cont, m_header); } IntervalIndexIFace * IndexFactory::CreateIndex(ModelReaderPtr reader) { - IntervalIndexIFace * p; - - switch (m_header.GetVersion()) - { - case FHeaderT::v1: - p = new old_101::IntervalIndex(reader); - break; - - default: - p = new IntervalIndex(reader); - break; - } - - return p; + if (m_version.format == version::v1) + return new old_101::IntervalIndex(reader); + return new IntervalIndex(reader); } diff --git a/indexer/data_factory.hpp b/indexer/data_factory.hpp index c4e4c140a9..afdc297284 100644 --- a/indexer/data_factory.hpp +++ b/indexer/data_factory.hpp @@ -1,5 +1,6 @@ #pragma once #include "data_header.hpp" +#include "mwm_version.hpp" #include "../coding/reader.hpp" @@ -9,11 +10,13 @@ class IntervalIndexIFace; class IndexFactory { + version::MwmVersion m_version; feature::DataHeader m_header; public: void Load(FilesContainerR const & cont); + inline version::MwmVersion const & GetMwmVersion() const { return m_version; } inline feature::DataHeader const & GetHeader() const { return m_header; } IntervalIndexIFace * CreateIndex(ModelReaderPtr reader); diff --git a/indexer/data_header.cpp b/indexer/data_header.cpp index c07ed87de7..b3fb87f147 100644 --- a/indexer/data_header.cpp +++ b/indexer/data_header.cpp @@ -93,7 +93,8 @@ namespace feature WriteVarInt(w, static_cast(m_type)); } - void DataHeader::Load(ModelReaderPtr const & r, Version ver /*= unknownVersion*/) + void DataHeader::Load(ModelReaderPtr const & r, + version::Format format /* = version::unknownFormat */) { ReaderSource src(r); m_codingParams.Load(src); @@ -105,7 +106,7 @@ namespace feature LoadBytes(src, m_langs); m_type = static_cast(ReadVarInt(src)); - m_ver = ver; + m_format = format; if (!IsMWMSuitable()) { @@ -117,7 +118,7 @@ namespace feature // Place all new serializable staff here. } - void DataHeader::LoadVer1(ModelReaderPtr const & r) + void DataHeader::LoadV1(ModelReaderPtr const & r) { ReaderSource src(r); int64_t const base = ReadPrimitiveFromSource(src); @@ -132,6 +133,6 @@ namespace feature m_type = country; - m_ver = v1; + m_format = version::v1; } } diff --git a/indexer/data_header.hpp b/indexer/data_header.hpp index 499fde49ba..32a3b064f7 100644 --- a/indexer/data_header.hpp +++ b/indexer/data_header.hpp @@ -1,6 +1,7 @@ #pragma once #include "coding_params.hpp" +#include "mwm_version.hpp" #include "../geometry/rect2d.hpp" @@ -59,24 +60,15 @@ namespace feature pair GetScaleRange() const; - enum Version - { - unknownVersion = -1, - v1 = 0, // April 2011 - v2, // November 2011 (store type index, instead of raw type in mwm) - v3, // March 2013 (store type index, instead of raw type in search data) - lastVersion = v3 - }; - - inline Version GetVersion() const { return m_ver; } - inline bool IsMWMSuitable() const { return (m_ver <= lastVersion); } + inline version::Format GetFormat() const { return m_format; } + inline bool IsMWMSuitable() const { return m_format <= version::lastFormat; } /// @name Serialization //@{ void Save(FileWriter & w) const; - void Load(ModelReaderPtr const & r, Version ver = unknownVersion); - void LoadVer1(ModelReaderPtr const & r); + void Load(ModelReaderPtr const & r, version::Format format = version::unknownFormat); + void LoadV1(ModelReaderPtr const & r); //@} enum MapType @@ -90,7 +82,7 @@ namespace feature inline MapType GetType() const { return m_type; } private: - Version m_ver; + version::Format m_format; MapType m_type; }; } diff --git a/indexer/feature_loader_base.cpp b/indexer/feature_loader_base.cpp index 6b6f72e90d..963eab0e5d 100644 --- a/indexer/feature_loader_base.cpp +++ b/indexer/feature_loader_base.cpp @@ -56,19 +56,12 @@ SharedLoadInfo::ReaderT SharedLoadInfo::GetTrianglesReader(int ind) const void SharedLoadInfo::CreateLoader() { - switch (m_header.GetVersion()) - { - case DataHeader::v1: + if (m_header.GetFormat() == version::v1) m_pLoader = new old_101::feature::LoaderImpl(*this); - break; - - default: + else m_pLoader = new LoaderCurrent(*this); - break; - } } - //////////////////////////////////////////////////////////////////////////////////////////// // LoaderBase implementation. //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indexer/index.cpp b/indexer/index.cpp index 724e0fede3..5566c80a56 100644 --- a/indexer/index.cpp +++ b/indexer/index.cpp @@ -26,22 +26,11 @@ string MwmValue::GetFileName() const return s; } -////////////////////////////////////////////////////////////////////////////////// -// Index::MwmLock implementation -////////////////////////////////////////////////////////////////////////////////// - -string Index::MwmLock::GetFileName() const -{ - MwmValue * p = GetValue(); - return (p ? p->GetFileName() : string()); -} - ////////////////////////////////////////////////////////////////////////////////// // Index implementation ////////////////////////////////////////////////////////////////////////////////// -bool Index::GetVersion(string const & name, MwmInfo & info, - feature::DataHeader::Version & version) const +bool Index::GetVersion(string const & name, MwmInfo & info) { MwmValue value(name); @@ -54,8 +43,8 @@ bool Index::GetVersion(string const & name, MwmInfo & info, pair const scaleR = h.GetScaleRange(); info.m_minScale = static_cast(scaleR.first); info.m_maxScale = static_cast(scaleR.second); + info.m_version = value.GetMwmVersion(); - version = h.GetVersion(); return true; } @@ -104,30 +93,28 @@ namespace } } -bool Index::RegisterMap(string const & fileName, m2::RectD & rect, - feature::DataHeader::Version & version) +pair Index::RegisterMap(string const & fileName) { if (GetPlatform().IsFileExistsByFullPath(GetFullPath(fileName + READY_FILE_EXTENSION))) { - UpdateStatus status = UpdateMap(fileName, rect, version); - switch (status) + pair updateResult = UpdateMap(fileName); + switch (updateResult.second) { case UPDATE_STATUS_OK: - return true; + return make_pair(move(updateResult.first), true); case UPDATE_STATUS_BAD_FILE: - return false; + return make_pair(move(updateResult.first), false); case UPDATE_STATUS_UPDATE_DELAYED: // Not dangerous, but it's strange when adding existing maps. ASSERT(false, ()); - version = feature::DataHeader::v3; - return true; + return make_pair(move(updateResult.first), true); } } - if (!Register(fileName, rect, version)) - return false; - m_observers.ForEach(&Observer::OnMapRegistered, fileName); - return true; + pair result = Register(fileName); + if (result.second) + m_observers.ForEach(&Observer::OnMapRegistered, fileName); + return result; } bool Index::DeleteMap(string const & fileName) @@ -154,10 +141,11 @@ bool Index::RemoveObserver(Observer & observer) return m_observers.Remove(observer); } -Index::UpdateStatus Index::UpdateMap(string const & fileName, m2::RectD & rect, - feature::DataHeader::Version & version) +pair Index::UpdateMap(string const & fileName) { - UpdateStatus status = UPDATE_STATUS_OK; + pair result; + result.second = UPDATE_STATUS_BAD_FILE; + { lock_guard lock(m_lock); @@ -165,19 +153,24 @@ Index::UpdateStatus Index::UpdateMap(string const & fileName, m2::RectD & rect, if (id != INVALID_MWM_ID && m_info[id].m_lockCount > 0) { m_info[id].SetStatus(MwmInfo::STATUS_PENDING_UPDATE); - status = UPDATE_STATUS_UPDATE_DELAYED; + result.first = GetLock(id); + result.second = UPDATE_STATUS_UPDATE_DELAYED; } else { ReplaceFileWithReady(fileName); - status = RegisterImpl(fileName, rect, version) ? UPDATE_STATUS_OK : UPDATE_STATUS_BAD_FILE; + pair registerResult = RegisterImpl(fileName); + if (registerResult.second) { + result.first = move(registerResult.first); + result.second = UPDATE_STATUS_OK; + } } } - if (status != UPDATE_STATUS_BAD_FILE) + if (result.second != UPDATE_STATUS_BAD_FILE) m_observers.ForEach(&Observer::OnMapUpdateIsReady, fileName); - if (status == UPDATE_STATUS_OK) + if (result.second == UPDATE_STATUS_OK) m_observers.ForEach(&Observer::OnMapUpdated, fileName); - return status; + return result; } void Index::UpdateMwmInfo(MwmId id) @@ -214,19 +207,26 @@ void Index::UpdateMwmInfo(MwmId id) ////////////////////////////////////////////////////////////////////////////////// Index::FeaturesLoaderGuard::FeaturesLoaderGuard(Index const & parent, MwmId id) - : m_lock(parent, id), - /// @note This guard is suitable when mwm is loaded - m_vector(m_lock.GetValue()->m_cont, m_lock.GetValue()->GetHeader()) + : m_lock(const_cast(parent), id), + /// @note This guard is suitable when mwm is loaded + m_vector(m_lock.GetValue()->m_cont, m_lock.GetValue()->GetHeader()) { } +string Index::FeaturesLoaderGuard::GetFileName() const +{ + if (!m_lock.IsLocked()) + return string(); + return m_lock.GetValue()->GetFileName(); +} + bool Index::FeaturesLoaderGuard::IsWorld() const { - return (m_lock.GetValue()->GetHeader().GetType() == feature::DataHeader::world); + return m_lock.GetValue()->GetHeader().GetType() == feature::DataHeader::world; } void Index::FeaturesLoaderGuard::GetFeature(uint32_t offset, FeatureType & ft) { m_vector.Get(offset, ft); - ft.SetID(FeatureID(m_lock.GetID(), offset)); + ft.SetID(FeatureID(m_lock.GetId(), offset)); } diff --git a/indexer/index.hpp b/indexer/index.hpp index aa21d9f714..c8356a10b1 100644 --- a/indexer/index.hpp +++ b/indexer/index.hpp @@ -10,10 +10,12 @@ #include "../defines.hpp" +#include "../base/macros.hpp" #include "../base/observer_list.hpp" #include "../std/algorithm.hpp" #include "../std/unordered_set.hpp" +#include "../std/utility.hpp" #include "../std/vector.hpp" class MwmValue : public MwmSet::MwmValueBase @@ -25,6 +27,7 @@ public: explicit MwmValue(string const & name); inline feature::DataHeader const & GetHeader() const { return m_factory.GetHeader(); } + inline version::MwmVersion const & GetMwmVersion() const { return m_factory.GetMwmVersion(); } /// @return MWM file name without extension. string GetFileName() const; @@ -34,8 +37,7 @@ class Index : public MwmSet { protected: // MwmSet overrides: - bool GetVersion(string const & name, MwmInfo & info, - feature::DataHeader::Version & version) const override; + bool GetVersion(string const & name, MwmInfo & info) override; MwmValue * CreateValue(string const & name) const override; void UpdateMwmInfo(MwmId id) override; @@ -72,43 +74,28 @@ public: Index(); ~Index(); - class MwmLock : public MwmSet::MwmLock - { - typedef MwmSet::MwmLock BaseT; - public: - MwmLock(Index const & index, MwmId mwmId) - : BaseT(const_cast(index), mwmId) {} - - inline MwmValue * GetValue() const - { - return static_cast(BaseT::GetValue()); - } - - /// @return MWM file name without extension. - /// If value is 0, an empty string returned. - string GetFileName() const; - }; - /// Registers new map. /// - /// \return True if map was successfully registered. In this case - /// version is set to the file format version. Otherwise - /// returns false and version is not modified. This means - /// that file isn't suitable, for example, because of - /// greater version. - bool RegisterMap(string const & fileName, m2::RectD & rect, - feature::DataHeader::Version & version); + /// \return A pair of MwmLock and a flag. MwmLock is locked iff map + /// with fileName was created or already exists. Flag is + /// set when a new map was registered. Thus, there are + /// three main cases: + /// * map already exists - returns active lock and unset flag + /// * a new map was registered - returns active lock and set flag + /// * can't register new map - returns inactive lock and unset flag + WARN_UNUSED_RESULT pair RegisterMap(string const & fileName); /// Replaces 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 UPDATE_STATUS_OK, when map file have updated, as a side effect - /// sets version to an mwm format version. - /// UPDATE_STATUS_BAD_FILE when file isn't suitable for update. - /// UPDATE_STATUS_UPDATE_DELAYED when update is delayed. - UpdateStatus UpdateMap(string const & fileName, m2::RectD & rect, - feature::DataHeader::Version & version); + /// \return * map file have been updated - returns active lock and + /// UPDATE_STATUS_OK + /// * update is delayed because map is busy - returns active lock and + /// UPDATE_STATUS_UPDATE_DELAYED + /// * file isn't suitable for update - returns inactive lock and + /// UPDATE_STATUS_BAD_FILE + WARN_UNUSED_RESULT pair UpdateMap(string const & fileName); /// Deletes map both from file system and internal tables, also, /// deletes all files related to the map. If map was successfully @@ -161,7 +148,7 @@ private: void operator() (MwmLock const & lock, covering::CoveringGetter & cov, uint32_t scale) const { - MwmValue * pValue = lock.GetValue(); + MwmValue * pValue = lock.GetValue(); if (pValue) { feature::DataHeader const & header = pValue->GetHeader(); @@ -181,7 +168,7 @@ private: pValue->m_factory); // iterate through intervals - ImplFunctor implF(fv, m_f, lock.GetID()); + ImplFunctor implF(fv, m_f, lock.GetId()); for (size_t i = 0; i < interval.size(); ++i) index.ForEachInIntervalAndScale(implF, interval[i].first, interval[i].second, scale); } @@ -217,7 +204,7 @@ private: void operator() (MwmLock const & lock, covering::CoveringGetter & cov, uint32_t scale) const { - MwmValue * pValue = lock.GetValue(); + MwmValue * pValue = lock.GetValue(); if (pValue) { feature::DataHeader const & header = pValue->GetHeader(); @@ -234,7 +221,7 @@ private: pValue->m_factory); // iterate through intervals - ImplFunctor implF(m_f, lock.GetID()); + ImplFunctor implF(m_f, lock.GetId()); for (size_t i = 0; i < interval.size(); ++i) index.ForEachInIntervalAndScale(implF, interval[i].first, interval[i].second, scale); } @@ -286,17 +273,17 @@ public: /// Guard for loading features from particular MWM by demand. class FeaturesLoaderGuard { - MwmLock m_lock; - FeaturesVector m_vector; - public: FeaturesLoaderGuard(Index const & parent, MwmId id); - inline MwmSet::MwmId GetID() const { return m_lock.GetID(); } - inline string GetFileName() const { return m_lock.GetFileName(); } - + inline MwmSet::MwmId GetId() const { return m_lock.GetId(); } + string GetFileName() const; bool IsWorld() const; void GetFeature(uint32_t offset, FeatureType & ft); + + private: + MwmLock m_lock; + FeaturesVector m_vector; }; MwmId GetMwmIdByName(string const & name) const @@ -320,8 +307,8 @@ public: { if (id != INVALID_MWM_ID) { - MwmLock lock(*this, id); - if (lock.GetValue()) + MwmLock lock(const_cast(*this), id); + if (lock.IsLocked()) { covering::CoveringGetter cov(rect, covering::ViewportWithLowLevels); ReadMWMFunctor fn(f); @@ -339,8 +326,8 @@ private: ASSERT_LESS(index, features.size(), ()); size_t result = index; MwmId id = features[index].m_mwm; - MwmLock lock(*this, id); - MwmValue * pValue = lock.GetValue(); + MwmLock lock(const_cast(*this), id); + MwmValue * pValue = lock.GetValue(); if (pValue) { FeaturesVector featureReader(pValue->m_cont, pValue->GetHeader()); @@ -386,7 +373,7 @@ private: { case MwmInfo::COUNTRY: { - MwmLock lock(*this, id); + MwmLock lock(const_cast(*this), id); f(lock, cov, scale); } break; @@ -404,13 +391,13 @@ private: if (worldID[0] < count) { - MwmLock lock(*this, worldID[0]); + MwmLock lock(const_cast(*this), worldID[0]); f(lock, cov, scale); } if (worldID[1] < count) { - MwmLock lock(*this, worldID[1]); + MwmLock lock(const_cast(*this), worldID[1]); f(lock, cov, scale); } } diff --git a/indexer/indexer_tests/index_test.cpp b/indexer/indexer_tests/index_test.cpp index 7fbd85b4e1..aabe4c7427 100644 --- a/indexer/indexer_tests/index_test.cpp +++ b/indexer/indexer_tests/index_test.cpp @@ -75,10 +75,7 @@ private: UNIT_TEST(Index_Parse) { Index index; - - m2::RectD dummyRect; - feature::DataHeader::Version dummyVersion; - index.RegisterMap("minsk-pass" DATA_FILE_EXTENSION, dummyRect, dummyVersion); + index.RegisterMap("minsk-pass" DATA_FILE_EXTENSION); // Make sure that index is actually parsed. NoopFunctor fn; @@ -102,31 +99,49 @@ UNIT_TEST(Index_MwmStatusNotifications) index.AddObserver(observer); TEST_EQUAL(0, observer.map_registered_calls(), ()); - m2::RectD dummyRect; - feature::DataHeader::Version dummyVersion; // Check that observers are triggered after map registration. - TEST(index.RegisterMap(testMapName, dummyRect, dummyVersion), ()); - TEST_EQUAL(1, observer.map_registered_calls(), ()); + { + pair p = index.RegisterMap(testMapName); + TEST(p.first.IsLocked(), ()); + TEST(p.second, ()); + TEST_EQUAL(1, observer.map_registered_calls(), ()); + } // Check that map can't registered twice and observers aren't // triggered. - TEST(!index.RegisterMap(testMapName, dummyRect, dummyVersion), ()); - TEST_EQUAL(1, observer.map_registered_calls(), ()); + { + pair p = index.RegisterMap(testMapName); + TEST(p.first.IsLocked(), ()); + TEST(!p.second, ()); + TEST_EQUAL(1, observer.map_registered_calls(), ()); + } TEST(my::CopyFileX(testMapPath, testMapUpdatePath), ()); MY_SCOPE_GUARD(testMapUpdateGuard, bind(&CheckedDeleteFile, testMapUpdatePath)); // Check that observers are notified when map is deleted. - TEST_EQUAL(0, observer.map_update_is_ready_calls(), ()); - TEST_EQUAL(0, observer.map_updated_calls(), ()); - TEST_EQUAL(Index::UPDATE_STATUS_OK, index.UpdateMap(testMapName, dummyRect, dummyVersion), ()); - TEST_EQUAL(1, observer.map_update_is_ready_calls(), ()); - TEST_EQUAL(1, observer.map_updated_calls(), ()); + { + TEST_EQUAL(0, observer.map_update_is_ready_calls(), ()); + TEST_EQUAL(0, observer.map_updated_calls(), ()); + pair p = index.UpdateMap(testMapName); + 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(), ()); + } - // Check that observers are notified when map is deleted. - TEST_EQUAL(0, observer.map_deleted_calls(), ()); - TEST(index.DeleteMap(testMapName), ()); + // Try to delete map in presence of active lock. Map should be + // marked "to be removed" but can't be deleted. + { + MwmSet::MwmLock lock(index, testMapName); + TEST(lock.IsLocked(), ()); + + TEST(!index.DeleteMap(testMapName), ()); + TEST_EQUAL(0, observer.map_deleted_calls(), ()); + } + + // Check that observers are notified when lock is destroyed. TEST_EQUAL(1, observer.map_deleted_calls(), ()); index.RemoveObserver(observer); diff --git a/indexer/indexer_tests/mwm_set_test.cpp b/indexer/indexer_tests/mwm_set_test.cpp index 6b1f15b520..b167b1948e 100644 --- a/indexer/indexer_tests/mwm_set_test.cpp +++ b/indexer/indexer_tests/mwm_set_test.cpp @@ -11,15 +11,15 @@ namespace class TestMwmSet : public MwmSet { protected: - virtual bool GetVersion(string const & path, MwmInfo & info, - feature::DataHeader::Version & version) const + virtual bool GetVersion(string const & path, MwmInfo & info) { int n = path[0] - '0'; info.m_maxScale = n; info.m_limitRect = m2::RectD(0, 0, 1, 1); - version = feature::DataHeader::lastVersion; + info.m_version.format = version::lastFormat; return true; } + virtual MwmValue * CreateValue(string const &) const { return new MwmValue(); @@ -53,8 +53,8 @@ UNIT_TEST(MwmSetSmokeTest) { MwmSet::MwmLock lock0(mwmSet, 0); MwmSet::MwmLock lock1(mwmSet, 1); - TEST(lock0.GetValue() != NULL, ()); - TEST(lock1.GetValue() == NULL, ()); + TEST(lock0.IsLocked(), ()); + TEST(!lock1.IsLocked(), ()); } mwmSet.Register("3"); @@ -69,7 +69,7 @@ UNIT_TEST(MwmSetSmokeTest) { MwmSet::MwmLock lock(mwmSet, 1); - TEST(lock.GetValue() != NULL, ()); + TEST(lock.IsLocked(), ()); mwmSet.Deregister("3"); mwmSet.Register("4"); } diff --git a/indexer/mwm_set.cpp b/indexer/mwm_set.cpp index 359640066d..608100b3fe 100644 --- a/indexer/mwm_set.cpp +++ b/indexer/mwm_set.cpp @@ -3,12 +3,15 @@ #include "../defines.hpp" +#include "../base/assert.hpp" #include "../base/logging.hpp" -#include "../base/macros.hpp" #include "../base/stl_add.hpp" #include "../std/algorithm.hpp" +// static +MwmSet::MwmId const MwmSet::INVALID_MWM_ID = static_cast(-1); + MwmInfo::MwmInfo() : m_lockCount(0), m_status(STATUS_DEREGISTERED) { // Important: STATUS_DEREGISTERED - is the default value. @@ -23,17 +26,54 @@ MwmInfo::MwmTypeT MwmInfo::GetType() const return COASTS; } +MwmSet::MwmLock::MwmLock() : m_mwmSet(nullptr), m_mwmId(MwmSet::INVALID_MWM_ID), m_value(nullptr) {} + MwmSet::MwmLock::MwmLock(MwmSet & mwmSet, MwmId mwmId) - : m_mwmSet(mwmSet), m_id(mwmId), m_pValue(mwmSet.LockValue(mwmId)) + : m_mwmSet(&mwmSet), m_mwmId(mwmId), m_value(m_mwmSet->LockValue(m_mwmId)) { } +MwmSet::MwmLock::MwmLock(MwmSet & mwmSet, string const & fileName) + : m_mwmSet(&mwmSet), m_mwmId(MwmSet::INVALID_MWM_ID), m_value(nullptr) +{ + lock_guard lock(m_mwmSet->m_lock); + m_mwmId = m_mwmSet->GetIdByName(fileName); + if (m_mwmId != MwmSet::INVALID_MWM_ID) + m_value = m_mwmSet->LockValueImpl(m_mwmId); +} + +MwmSet::MwmLock::MwmLock(MwmSet & mwmSet, MwmId mwmId, MwmValueBase * value) + : m_mwmSet(&mwmSet), m_mwmId(mwmId), m_value(value) +{ +} + +MwmSet::MwmLock::MwmLock(MwmLock && lock) + : m_mwmSet(lock.m_mwmSet), m_mwmId(lock.m_mwmId), m_value(lock.m_value) +{ + lock.m_mwmId = 0; + lock.m_mwmId = MwmSet::INVALID_MWM_ID; + lock.m_value = 0; +} + MwmSet::MwmLock::~MwmLock() { - if (m_pValue) - m_mwmSet.UnlockValue(m_id, m_pValue); + if (m_mwmSet && m_value) + m_mwmSet->UnlockValue(m_mwmId, m_value); } +MwmInfo const & MwmSet::MwmLock::GetInfo() const +{ + ASSERT(IsLocked(), ("MwmLock is not active.")); + return m_mwmSet->GetMwmInfo(m_mwmId); +} + +MwmSet::MwmLock & MwmSet::MwmLock::operator=(MwmLock && lock) +{ + swap(m_mwmSet, lock.m_mwmSet); + swap(m_mwmId, lock.m_mwmId); + swap(m_value, lock.m_value); + return *this; +} MwmSet::MwmSet(size_t cacheSize) : m_cacheSize(cacheSize) @@ -102,8 +142,7 @@ MwmSet::MwmId MwmSet::GetIdByName(string const & name) return INVALID_MWM_ID; } -bool MwmSet::Register(string const & fileName, m2::RectD & rect, - feature::DataHeader::Version & version) +pair MwmSet::Register(string const & fileName) { lock_guard lock(m_lock); @@ -114,20 +153,18 @@ bool MwmSet::Register(string const & fileName, m2::RectD & rect, LOG(LWARNING, ("Trying to add already registered map", fileName)); else m_info[id].SetStatus(MwmInfo::STATUS_UP_TO_DATE); - - return false; + return make_pair(GetLock(id), false); } - return RegisterImpl(fileName, rect, version); + return RegisterImpl(fileName); } -bool MwmSet::RegisterImpl(string const & fileName, m2::RectD & rect, - feature::DataHeader::Version & version) +pair MwmSet::RegisterImpl(string const & fileName) { // this function can throw an exception for bad mwm file MwmInfo info; - if (!GetVersion(fileName, info, version)) - return false; + if (!GetVersion(fileName, info)) + return make_pair(MwmLock(), false); info.SetStatus(MwmInfo::STATUS_UP_TO_DATE); @@ -135,9 +172,7 @@ bool MwmSet::RegisterImpl(string const & fileName, m2::RectD & rect, m_name[id] = fileName; m_info[id] = info; - rect = info.m_limitRect; - ASSERT(rect.IsValid(), ()); - return true; + return make_pair(GetLock(id), true); } bool MwmSet::DeregisterImpl(MwmId id) @@ -207,10 +242,21 @@ void MwmSet::GetMwmInfo(vector & info) const info = m_info; } +MwmInfo const & MwmSet::GetMwmInfo(MwmId id) const +{ + MwmSet * p = const_cast(this); + lock_guard lock(p->m_lock); + return m_info[id]; +} + MwmSet::MwmValueBase * MwmSet::LockValue(MwmId id) { lock_guard lock(m_lock); + return LockValueImpl(id); +} +MwmSet::MwmValueBase * MwmSet::LockValueImpl(MwmId id) +{ ASSERT_LESS(id, m_info.size(), ()); if (id >= m_info.size()) return NULL; @@ -237,7 +283,11 @@ MwmSet::MwmValueBase * MwmSet::LockValue(MwmId id) void MwmSet::UnlockValue(MwmId id, MwmValueBase * p) { lock_guard lock(m_lock); + UnlockValueImpl(id, p); +} +void MwmSet::UnlockValueImpl(MwmId id, MwmValueBase * p) +{ ASSERT(p, (id)); ASSERT_LESS(id, m_info.size(), ()); if (id >= m_info.size() || p == 0) diff --git a/indexer/mwm_set.hpp b/indexer/mwm_set.hpp index 6d045a6877..217c95fbce 100644 --- a/indexer/mwm_set.hpp +++ b/indexer/mwm_set.hpp @@ -1,9 +1,11 @@ #pragma once -#include "data_header.hpp" +#include "mwm_version.hpp" #include "../geometry/rect2d.hpp" +#include "../base/macros.hpp" + #include "../std/deque.hpp" #include "../std/mutex.hpp" #include "../std/string.hpp" @@ -31,10 +33,11 @@ public: MwmInfo(); - m2::RectD m_limitRect; ///< Limit rect of mwm. - uint8_t m_minScale; ///< Min zoom level of mwm. - uint8_t m_maxScale; ///< Max zoom level of mwm. - uint8_t m_lockCount; ///< Number of locks. + m2::RectD m_limitRect; ///< Limit rect of mwm. + uint8_t m_minScale; ///< Min zoom level of mwm. + uint8_t m_maxScale; ///< Max zoom level of mwm. + uint8_t m_lockCount; ///< Number of locks. + version::MwmVersion m_version; ///< Mwm file version. inline bool IsRegistered() const { @@ -58,6 +61,8 @@ class MwmSet public: typedef size_t MwmId; + static const MwmId INVALID_MWM_ID; + explicit MwmSet(size_t cacheSize = 5); virtual ~MwmSet() = 0; @@ -71,42 +76,54 @@ public: class MwmLock { public: + MwmLock(); MwmLock(MwmSet & mwmSet, MwmId mwmId); - ~MwmLock(); + MwmLock(MwmSet & mwmSet, string const & fileName); + MwmLock(MwmLock && lock); + virtual ~MwmLock(); - inline MwmValueBase * GetValue() const { return m_pValue; } - inline MwmId GetID() const { return m_id; } + template + inline T * GetValue() const + { + return static_cast(m_value); + } + inline bool IsLocked() const { return m_value; } + inline MwmId GetId() const { return m_mwmId; } + MwmInfo const & GetInfo() const; + + MwmLock & operator=(MwmLock && lock); private: - MwmSet & m_mwmSet; - MwmId m_id; - MwmValueBase * m_pValue; + friend class MwmSet; + + MwmLock(MwmSet & mwmSet, MwmId mwmId, MwmValueBase * value); + + MwmSet * m_mwmSet; + MwmId m_mwmId; + MwmValueBase * m_value; + + NONCOPYABLE(MwmLock); }; /// Registers new map in the set. - /// @param[in] fileName File name (without full path) of country. - /// @param[out] rect Limit rect of country. - /// @param[out] version Version of the file. /// - /// @return True when map is registered, false otherwise - map already - /// exists or it's not possible to get mwm's version. + /// \param fileName File name (without full path) of country. + /// + /// \return A pair of MwmLock and a flag. MwmLock is locked iff map + /// with fileName was created or already exists. Flag is + /// set when a new map was registered. Thus, there are + /// three main cases: + /// * map already exists - returns active lock and unset flag + /// * a new map was registered - returns active lock and set flag + /// * can't register new map - returns inactive lock and unset flag //@{ protected: - bool RegisterImpl(string const & fileName, m2::RectD & rect, - feature::DataHeader::Version & version); + WARN_UNUSED_RESULT pair RegisterImpl(string const & fileName); public: - bool Register(string const & fileName, m2::RectD & rect, feature::DataHeader::Version & version); + WARN_UNUSED_RESULT pair Register(string const & fileName); //@} - /// Used in unit tests only. - inline void Register(string const & fileName) - { - m2::RectD dummyRect; - feature::DataHeader::Version dummyVersion; - CHECK(Register(fileName, dummyRect, dummyVersion), ()); - } - /// @name Remove mwm. //@{ protected: @@ -130,14 +147,17 @@ public: /// In that case, LockValue returns NULL. void GetMwmInfo(vector & info) const; + /// \return A reference to an MwmInfo corresponding to id. Id must + /// be a valid Mwm id. + MwmInfo const & GetMwmInfo(MwmId id) const; + // Clear caches. void ClearCache(); protected: /// @return True when it's possible to get file format version - in /// this case version is set to the file format version. - virtual bool GetVersion(string const & name, MwmInfo & info, - feature::DataHeader::Version & version) const = 0; + virtual bool GetVersion(string const & name, MwmInfo & info) = 0; virtual MwmValueBase * CreateValue(string const & name) const = 0; void Cleanup(); @@ -146,7 +166,9 @@ private: typedef deque > CacheType; MwmValueBase * LockValue(MwmId id); + MwmValueBase * LockValueImpl(MwmId id); void UnlockValue(MwmId id, MwmValueBase * p); + void UnlockValueImpl(MwmId id, MwmValueBase * p); /// Find first removed mwm or add a new one. /// @precondition This function is always called under mutex m_lock. @@ -160,8 +182,6 @@ private: size_t m_cacheSize; protected: - static const MwmId INVALID_MWM_ID = static_cast(-1); - /// Find mwm with a given name. /// @precondition This function is always called under mutex m_lock. MwmId GetIdByName(string const & name); @@ -169,6 +189,12 @@ protected: /// @precondition This function is always called under mutex m_lock. void ClearCache(MwmId id); + /// @precondition This function is always called under mutex m_lock. + WARN_UNUSED_RESULT inline MwmLock GetLock(MwmId id) + { + return MwmLock(*this, id, LockValueImpl(id)); + } + /// Update given MwmInfo. /// @precondition This function is always called under mutex m_lock. virtual void UpdateMwmInfo(MwmId id); diff --git a/indexer/mwm_version.cpp b/indexer/mwm_version.cpp index 993623dddb..ece98cae06 100644 --- a/indexer/mwm_version.cpp +++ b/indexer/mwm_version.cpp @@ -1,54 +1,79 @@ #include "mwm_version.hpp" #include "data_header.hpp" +#include "../coding/file_container.hpp" +#include "../coding/reader_wrapper.hpp" #include "../coding/varint.hpp" #include "../coding/writer.hpp" -#include "../coding/reader_wrapper.hpp" +#include "../base/logging.hpp" #include "../base/timer.hpp" +#include "../defines.hpp" -namespace ver { +#include "../std/ctime.hpp" +namespace version +{ +namespace +{ typedef feature::DataHeader FHeaderT; -char MWM_PROLOG[] = "MWM"; +char const MWM_PROLOG[] = "MWM"; -void WriteVersion(Writer & w) -{ - w.Write(MWM_PROLOG, ARRAY_SIZE(MWM_PROLOG)); - - // write inner data version - WriteVarUint(w, static_cast(FHeaderT::lastVersion)); - - // static is used for equal time stamp for all "mwm" files in one generation process - static uint32_t generatorStartTime = my::TodayAsYYMMDD(); - WriteVarUint(w, generatorStartTime); -} - -template uint32_t ReadVersionT(TSource & src) +template +void ReadVersionT(TSource & src, MwmVersion & version) { size_t const prologSize = ARRAY_SIZE(MWM_PROLOG); char prolog[prologSize]; src.Read(prolog, prologSize); if (strcmp(prolog, MWM_PROLOG) != 0) - return FHeaderT::v2; + { + version.format = v2; + version.timestamp = + my::GenerateTimestamp(2011 - 1900 /* number of years since 1900 */, + 10 /* number of month since January */, 1 /* month day */); + return; + } - return ReadVarUint(src); + uint32_t formatIndex = ReadVarUint(src); + if (formatIndex > lastFormat) + { + LOG(LERROR, ("Unknown file format index:", formatIndex)); + formatIndex = lastFormat; + } + version.format = static_cast(formatIndex); + version.timestamp = ReadVarUint(src); } +} // namespace -uint32_t ReadVersion(ModelReaderPtr const & r) +MwmVersion::MwmVersion() : format(unknownFormat), timestamp(0) {} + +void WriteVersion(Writer & w) { - ReaderSource src(r); - return ReadVersionT(src); + w.Write(MWM_PROLOG, ARRAY_SIZE(MWM_PROLOG)); + + // write inner data version + WriteVarUint(w, static_cast(lastFormat)); + + // static is used for equal time stamp for all "mwm" files in one generation process + static uint32_t generatorStartTime = my::TodayAsYYMMDD(); + WriteVarUint(w, generatorStartTime); } -uint32_t ReadTimestamp(ReaderSrc & src) +void ReadVersion(ReaderSrc & src, MwmVersion & version) { - (void)ReadVersionT(src); - - return ReadVarUint(src); + ReadVersionT(src, version); } +bool ReadVersion(FilesContainerR const & container, MwmVersion & version) +{ + if (!container.IsExist(VERSION_FILE_TAG)) + return false; + ModelReaderPtr versionReader = container.GetReader(VERSION_FILE_TAG); + ReaderSource src(versionReader); + ReadVersionT(src, version); + return true; } +} // namespace version diff --git a/indexer/mwm_version.hpp b/indexer/mwm_version.hpp index a41e0b0c91..89c986198a 100644 --- a/indexer/mwm_version.hpp +++ b/indexer/mwm_version.hpp @@ -2,18 +2,36 @@ #include "../std/stdint.hpp" - -class ModelReaderPtr; -class Writer; +class FilesContainerR; class ReaderSrc; +class Writer; -namespace ver +namespace version { - void WriteVersion(Writer & w); +enum Format +{ + unknownFormat = -1, + v1 = 0, // April 2011 + v2, // November 2011 (store type index, instead of raw type in mwm) + v3, // March 2013 (store type index, instead of raw type in search data) + lastFormat = v3 +}; - /// @return See feature::DataHeader::Version for more details. - uint32_t ReadVersion(ModelReaderPtr const & r); +struct MwmVersion { + MwmVersion(); - /// @return Data timestamp in yymmdd format. - uint32_t ReadTimestamp(ReaderSrc & src); -} + Format format; + uint32_t timestamp; +}; + +/// Writes latest format and current timestamp to the writer. +void WriteVersion(Writer & w); + +/// Reads mwm version from src. +void ReadVersion(ReaderSrc & src, MwmVersion & version); + +/// \return True when version was successfully parsed from container, +/// otherwise returns false. In the latter case version is +/// unchanged. +bool ReadVersion(FilesContainerR const & container, MwmVersion & version); +} // namespace version diff --git a/indexer/search_index_builder.cpp b/indexer/search_index_builder.cpp index 027e749633..c62507513f 100644 --- a/indexer/search_index_builder.cpp +++ b/indexer/search_index_builder.cpp @@ -383,7 +383,7 @@ void AddFeatureNameIndexPairs(FilesContainerR const & container, StringsFile & stringsFile) { feature::DataHeader header; - header.Load(container.GetReader(HEADER_FILE_TAG)); + header.Load(container.GetReader(HEADER_FILE_TAG), version::unknownFormat); FeaturesVector features(container, header); ValueBuilder valueBuilder; @@ -404,7 +404,7 @@ void BuildSearchIndex(FilesContainerR const & cont, CategoriesHolder const & cat { { feature::DataHeader header; - header.Load(cont.GetReader(HEADER_FILE_TAG)); + header.Load(cont.GetReader(HEADER_FILE_TAG), version::unknownFormat); FeaturesVector featuresV(cont, header); serial::CodingParams cp(search::GetCPForTrie(header.GetDefCodingParams())); diff --git a/map/benchmark_engine.cpp b/map/benchmark_engine.cpp index 94dd3b8296..8183065e94 100644 --- a/map/benchmark_engine.cpp +++ b/map/benchmark_engine.cpp @@ -133,9 +133,8 @@ void BenchmarkEngine::PrepareMaps() // add only maps needed for benchmarks MapsCollector collector; ForEachBenchmarkRecord(collector); - feature::DataHeader::Version version; for_each(collector.m_maps.begin(), collector.m_maps.end(), - bind(&Framework::RegisterMap, m_framework, _1, version)); + bind(&Framework::RegisterMap, m_framework, _1)); } BenchmarkEngine::BenchmarkEngine(Framework * fw) diff --git a/map/benchmark_tool/features_loading.cpp b/map/benchmark_tool/features_loading.cpp index efb6225336..957006104a 100644 --- a/map/benchmark_tool/features_loading.cpp +++ b/map/benchmark_tool/features_loading.cpp @@ -110,8 +110,7 @@ void RunFeaturesLoadingBenchmark(string const & file, pair scaleR, All return; model::FeaturesFetcher src; - feature::DataHeader::Version version; - src.RegisterMap(file, version); + src.RegisterMap(file); RunBenchmark(src, header.GetBounds(), scaleR, res); } diff --git a/map/feature_vec_model.cpp b/map/feature_vec_model.cpp index 3ad91ec761..ad412f4e75 100644 --- a/map/feature_vec_model.cpp +++ b/map/feature_vec_model.cpp @@ -32,24 +32,27 @@ void FeaturesFetcher::InitClassificator() } } -bool FeaturesFetcher::RegisterMap(string const & file, feature::DataHeader::Version & version) +pair FeaturesFetcher::RegisterMap(string const & file) { try { - m2::RectD r; - if (!m_multiIndex.RegisterMap(file, r, version)) + pair p = m_multiIndex.RegisterMap(file); + if (!p.second) { LOG(LWARNING, ("Can't add map", file, "Probably it's already added or has newer data version.")); - return false; + return p; } - m_rect.Add(r); - return true; + MwmSet::MwmLock & lock = p.first; + if (!lock.IsLocked()) + return p; + m_rect.Add(lock.GetInfo().m_limitRect); + return p; } catch (RootException const & e) { LOG(LERROR, ("IO error while adding ", file, " map. ", e.what())); - return false; + return make_pair(MwmSet::MwmLock(), false); } } @@ -62,10 +65,9 @@ bool FeaturesFetcher::DeleteMap(string const & file) return m_multiIndex.DeleteMap(file); } -bool FeaturesFetcher::UpdateMap(string const & file, m2::RectD & rect) +pair FeaturesFetcher::UpdateMap(string const & file) { - feature::DataHeader::Version version; - return m_multiIndex.UpdateMap(file, rect, version); + return m_multiIndex.UpdateMap(file); } //void FeaturesFetcher::Clean() diff --git a/map/feature_vec_model.hpp b/map/feature_vec_model.hpp index f0de9c28b3..e40830cb1a 100644 --- a/map/feature_vec_model.hpp +++ b/map/feature_vec_model.hpp @@ -9,6 +9,8 @@ #include "../coding/reader.hpp" #include "../coding/buffer_reader.hpp" +#include "../base/macros.hpp" + namespace model { //#define USE_BUFFER_READER @@ -30,11 +32,16 @@ namespace model public: void InitClassificator(); - /// @param[in] file Name of mwm file with extension. - //{@ - /// @return True when map was successfully registered, also, sets - /// version to the file format version. - bool RegisterMap(string const & file, feature::DataHeader::Version & version); + /// Registers new map. + /// + /// \return A pair of MwmLock and a flag. MwmLock is locked iff map + /// with fileName was created or already exists. Flag is + /// set when a new map was registered. Thus, there are + /// three main cases: + /// * map already exists - returns active lock and unset flag + /// * a new map was registered - returns active lock and set flag + /// * can't register new map - returns inactive lock and unset flag + WARN_UNUSED_RESULT pair RegisterMap(string const & file); /// Deregisters map denoted by file from internal records. void DeregisterMap(string const & file); @@ -47,12 +54,17 @@ namespace model /// \return True if map was successfully deleted. bool DeleteMap(string const & file); - /// Tries to update map denoted by file. If map is used right now, - /// update will be delayed. + /// Replaces 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 True when map was successfully updated, false when update - /// was delayed or when update's version is not good. - bool UpdateMap(string const & file, m2::RectD & rect); + /// \return * map file have been updated - returns active lock and + /// UPDATE_STATUS_OK + /// * update is delayed because map is busy - returns active lock and + /// UPDATE_STATUS_UPDATE_DELAYED + /// * file isn't suitable for update - returns inactive lock and + /// UPDATE_STATUS_BAD_FILE + WARN_UNUSED_RESULT pair UpdateMap(string const & file); //@} //void Clean(); diff --git a/map/framework.cpp b/map/framework.cpp index 446093381d..0cbe81fe26 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -22,6 +22,7 @@ #include "../indexer/categories_holder.hpp" #include "../indexer/feature.hpp" +#include "../indexer/mwm_version.hpp" #include "../indexer/scales.hpp" #include "../indexer/classificator_loader.hpp" @@ -84,26 +85,29 @@ namespace static const int BM_TOUCH_PIXEL_INCREASE = 20; } -bool Framework::RegisterMap(string const & file, feature::DataHeader::Version & version) +pair Framework::RegisterMap(string const & file) { LOG(LINFO, ("Loading map:", file)); - if (!m_model.RegisterMap(file, version)) - return false; + pair p = m_model.RegisterMap(file); + if (!p.second) + return p; + MwmSet::MwmLock & lock = p.first; + ASSERT(lock.IsLocked(), ()); - if (version == feature::DataHeader::v1) + MwmInfo const & info = lock.GetInfo(); + + 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)), ()); - - version = feature::DataHeader::unknownVersion; - return false; + return make_pair(MwmSet::MwmLock(), false); } - return true; + return p; } void Framework::DeregisterMap(string const & file) { m_model.DeregisterMap(file); } @@ -379,9 +383,12 @@ void Framework::UpdateAfterDownload(string const & fileName, TMapOptions opt) } // Add downloaded map. - m2::RectD rect; - if (m_model.UpdateMap(fileName, rect)) - InvalidateRect(rect, true); + pair p = m_model.UpdateMap(fileName); + if (p.second == Index::UPDATE_STATUS_OK) { + MwmSet::MwmLock & lock = p.first; + ASSERT(lock.IsLocked(), ()); + InvalidateRect(lock.GetInfo().m_limitRect, true); + } GetSearchEngine()->ClearViewportsCache(); } @@ -411,14 +418,18 @@ void Framework::RegisterAllMaps() GetMaps(maps); for_each(maps.begin(), maps.end(), [&](string const & file) { - feature::DataHeader::Version version; - if (RegisterMap(file, version) && version < minVersion) - minVersion = version; + pair p = RegisterMap(file); + if (p.second) + { + MwmSet::MwmLock & lock = p.first; + ASSERT(lock.IsLocked(), ()); + minVersion = min(minVersion, static_cast(lock.GetInfo().m_version.format)); + } }); m_countryTree.Init(maps); - GetSearchEngine()->SupportOldFormat(minVersion < feature::DataHeader::v3); + GetSearchEngine()->SupportOldFormat(minVersion < version::v3); } void Framework::DeregisterAllMaps() diff --git a/map/framework.hpp b/map/framework.hpp index 15bd80a419..7d35d231b3 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -174,7 +174,7 @@ public: /// /// @return True and inner mwm data version from header in version /// or false in case of errors. - bool RegisterMap(string const & file, feature::DataHeader::Version & version); + pair RegisterMap(string const & file); //@} /// Deletes all disk files corresponding to country. diff --git a/map/map_tests/bookmarks_test.cpp b/map/map_tests/bookmarks_test.cpp index f20ec89f87..920be3e355 100644 --- a/map/map_tests/bookmarks_test.cpp +++ b/map/map_tests/bookmarks_test.cpp @@ -400,9 +400,7 @@ UNIT_TEST(Bookmarks_AddressInfo) // Maps added in constructor (we need minsk-pass.mwm only) Framework fm; fm.DeregisterAllMaps(); - feature::DataHeader::Version version; - fm.RegisterMap("minsk-pass.mwm", version); - + fm.RegisterMap("minsk-pass.mwm"); fm.OnSize(800, 600); // assume that developers have English or Russian system language :) diff --git a/map/mwm_tests/multithread_mwm_test.cpp b/map/mwm_tests/multithread_mwm_test.cpp index 83b387e4cd..ce0854434f 100644 --- a/map/mwm_tests/multithread_mwm_test.cpp +++ b/map/mwm_tests/multithread_mwm_test.cpp @@ -63,8 +63,7 @@ namespace SourceT src; src.InitClassificator(); - feature::DataHeader::Version version; - src.RegisterMap(file + DATA_FILE_EXTENSION, version); + src.RegisterMap(file + DATA_FILE_EXTENSION); // Check that country rect is valid and not infinity. m2::RectD const r = src.GetWorldRect(); diff --git a/map/mwm_tests/mwm_foreach_test.cpp b/map/mwm_tests/mwm_foreach_test.cpp index a6ee0375e3..7eebb58e80 100644 --- a/map/mwm_tests/mwm_foreach_test.cpp +++ b/map/mwm_tests/mwm_foreach_test.cpp @@ -251,8 +251,7 @@ void RunTest(string const & file) model::FeaturesFetcher src1; src1.InitClassificator(); - feature::DataHeader::Version version; - src1.RegisterMap(file, version); + src1.RegisterMap(file); vector rects; rects.push_back(src1.GetWorldRect()); diff --git a/map/mwm_tests/mwm_index_test.cpp b/map/mwm_tests/mwm_index_test.cpp index a0ad429bf0..619f47d431 100644 --- a/map/mwm_tests/mwm_index_test.cpp +++ b/map/mwm_tests/mwm_index_test.cpp @@ -39,8 +39,14 @@ public: bool RunTest(string const & fileName, int lowS, int highS) { model::FeaturesFetcher src; - feature::DataHeader::Version version; - if (!src.RegisterMap(fileName, version) || version == feature::DataHeader::unknownVersion) + pair p = src.RegisterMap(fileName); + if (!p.second) + return false; + MwmSet::MwmLock & lock = p.first; + ASSERT(lock.IsLocked(), ()); + + version::Format version = lock.GetInfo().m_version.format; + if (version == version::unknownFormat) return false; CheckNonEmptyGeometry doCheck; diff --git a/routing/routing_mapping.cpp b/routing/routing_mapping.cpp index a3351ca67e..1c1fd42484 100644 --- a/routing/routing_mapping.cpp +++ b/routing/routing_mapping.cpp @@ -40,7 +40,13 @@ RoutingMapping::RoutingMapping(string const & fName, Index const * pIndex) ModelReaderPtr r2 = FilesContainerR(pl.GetReader(mwmName)).GetReader(VERSION_FILE_TAG); ReaderSrc src2(r2.GetPtr()); - if (ver::ReadTimestamp(src1) != ver::ReadTimestamp(src2)) + version::MwmVersion version1; + version::ReadVersion(src1, version1); + + version::MwmVersion version2; + version::ReadVersion(src2, version2); + + if (version1.timestamp != version2.timestamp) { m_container.Close(); m_isValid = false; diff --git a/search/house_detector.cpp b/search/house_detector.cpp index 85b2a9e6aa..59d915ce93 100644 --- a/search/house_detector.cpp +++ b/search/house_detector.cpp @@ -218,7 +218,7 @@ FeatureLoader::~FeatureLoader() void FeatureLoader::CreateLoader(size_t mwmID) { - if (m_pGuard == 0 || mwmID != m_pGuard->GetID()) + if (m_pGuard == 0 || mwmID != m_pGuard->GetId()) { delete m_pGuard; m_pGuard = new Index::FeaturesLoaderGuard(*m_pIndex, mwmID); diff --git a/search/locality_finder.cpp b/search/locality_finder.cpp index 8f2321b9b0..1ce4dc1b39 100644 --- a/search/locality_finder.cpp +++ b/search/locality_finder.cpp @@ -126,8 +126,8 @@ void LocalityFinder::RecreateCache(Cache & cache, m2::RectD rect) const for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId) { typedef feature::DataHeader HeaderT; - Index::MwmLock mwmLock(*m_pIndex, mwmId); - MwmValue * pMwm = mwmLock.GetValue(); + Index::MwmLock mwmLock(const_cast(*m_pIndex), mwmId); + MwmValue * pMwm = mwmLock.GetValue(); if (pMwm && pMwm->GetHeader().GetType() == HeaderT::world) { HeaderT const & header = pMwm->GetHeader(); diff --git a/search/search_query.cpp b/search/search_query.cpp index a467f3002f..1d65ea736b 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -263,8 +263,8 @@ void Query::UpdateViewportOffsets(MWMVectorT const & mwmInfo, m2::RectD const & // Search only mwms that intersect with viewport (world always does). if (rect.IsIntersect(mwmInfo[mwmId].m_limitRect)) { - Index::MwmLock mwmLock(*m_pIndex, mwmId); - if (MwmValue * pMwm = mwmLock.GetValue()) + Index::MwmLock mwmLock(const_cast(*m_pIndex), mwmId); + if (MwmValue * pMwm = mwmLock.GetValue()) { FHeaderT const & header = pMwm->GetHeader(); if (header.GetType() == FHeaderT::country) @@ -575,7 +575,7 @@ namespace impl // For the best performance, incoming id's should be sorted by id.first (mwm file id). void LoadFeature(FeatureID const & id, FeatureType & f, string & name, string & country) { - if (m_pFV.get() == 0 || m_pFV->GetID() != id.m_mwm) + if (m_pFV.get() == 0 || m_pFV->GetId() != id.m_mwm) m_pFV.reset(new Index::FeaturesLoaderGuard(*m_query.m_pIndex, id.m_mwm)); m_pFV->GetFeature(id.m_offset, f); @@ -1613,8 +1613,8 @@ void Query::SearchAddress(Results & res) for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId) { - Index::MwmLock mwmLock(*m_pIndex, mwmId); - MwmValue * pMwm = mwmLock.GetValue(); + Index::MwmLock mwmLock(const_cast(*m_pIndex), mwmId); + MwmValue * pMwm = mwmLock.GetValue(); if (pMwm && pMwm->m_cont.IsExist(SEARCH_INDEX_FILE_TAG) && pMwm->GetHeader().GetType() == FHeaderT::world) @@ -1666,8 +1666,11 @@ void Query::SearchAddress(Results & res) { for (MwmSet::MwmId id = 0; id < mwmInfo.size(); ++id) { - Index::MwmLock mwmLock(*m_pIndex, id); - if (m_pInfoGetter->IsBelongToRegion(mwmLock.GetFileName(), region.m_ids)) + Index::MwmLock mwmLock(const_cast(*m_pIndex), id); + string fileName; + if (mwmLock.IsLocked()) + fileName = mwmLock.GetValue()->GetFileName(); + if (m_pInfoGetter->IsBelongToRegion(fileName, region.m_ids)) SearchInMWM(mwmLock, params); } } @@ -2026,7 +2029,7 @@ void Query::SearchFeatures(Params const & params, MWMVectorT const & mwmInfo, Vi // Search only mwms that intersect with viewport (world always does). if (m_viewport[vID].IsIntersect(mwmInfo[mwmId].m_limitRect)) { - Index::MwmLock mwmLock(*m_pIndex, mwmId); + Index::MwmLock mwmLock(const_cast(*m_pIndex), mwmId); SearchInMWM(mwmLock, params, vID); } } @@ -2067,7 +2070,7 @@ void FillCategories(Query::Params const & params, TrieIterator const * pTrieRoot void Query::SearchInMWM(Index::MwmLock const & mwmLock, Params const & params, ViewportID vID /*= DEFAULT_V*/) { - if (MwmValue * pMwm = mwmLock.GetValue()) + if (MwmValue * pMwm = mwmLock.GetValue()) { if (pMwm->m_cont.IsExist(SEARCH_INDEX_FILE_TAG)) { @@ -2086,7 +2089,7 @@ void Query::SearchInMWM(Index::MwmLock const & mwmLock, Params const & params, trie::ValueReader(cp), trie::EdgeValueReader())); - MwmSet::MwmId const mwmId = mwmLock.GetID(); + MwmSet::MwmId const mwmId = mwmLock.GetId(); FeaturesFilter filter((vID == DEFAULT_V || isWorld) ? 0 : &m_offsetsInViewport[vID][mwmId], m_cancel); // Get categories for each token separately - find needed edge with categories. @@ -2270,10 +2273,11 @@ void Query::SearchAdditional(Results & res, bool nearMe, bool inViewport, size_t for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId) { - Index::MwmLock mwmLock(*m_pIndex, mwmId); - string const s = mwmLock.GetFileName(); - - if (s == name[0] || s == name[1]) + Index::MwmLock mwmLock(const_cast(*m_pIndex), mwmId); + string fileName; + if (mwmLock.IsLocked()) + fileName = mwmLock.GetValue()->GetFileName(); + if (fileName == name[0] || fileName == name[1]) SearchInMWM(mwmLock, params); } diff --git a/search/search_tests/house_detector_tests.cpp b/search/search_tests/house_detector_tests.cpp index 4a11789e68..96ee91adb8 100644 --- a/search/search_tests/house_detector_tests.cpp +++ b/search/search_tests/house_detector_tests.cpp @@ -183,9 +183,9 @@ UNIT_TEST(HS_StreetsMerge) classificator::Load(); Index index; - m2::RectD rect; - feature::DataHeader::Version version; - TEST(index.Register("minsk-pass.mwm", rect, version), ()); + pair p = index.Register("minsk-pass.mwm"); + TEST(p.first.IsLocked(), ()); + TEST(p.second, ()); { search::HouseDetector houser(&index); @@ -272,9 +272,9 @@ UNIT_TEST(HS_FindHouseSmoke) classificator::Load(); Index index; - m2::RectD rect; - feature::DataHeader::Version version; - index.Register("minsk-pass.mwm", rect, version); + pair p = index.Register("minsk-pass.mwm"); + TEST(p.first.IsLocked(), ()); + TEST(p.second, ()); { vector streetName(1, "Московская улица"); @@ -375,13 +375,13 @@ UNIT_TEST(HS_MWMSearch) } Index index; - m2::RectD rect; - feature::DataHeader::Version version; - if (!index.Register(country + ".mwm", rect, version)) + pair p = index.Register(country + ".mwm"); + if (!p.second) { LOG(LWARNING, ("MWM file not found")); return; } + TEST(p.first.IsLocked(), ()); CollectStreetIDs streetIDs; index.ForEachInScale(streetIDs, scales::GetUpperScale()); diff --git a/search/search_tests/locality_finder_test.cpp b/search/search_tests/locality_finder_test.cpp index dfd060e98e..3f564b2e26 100644 --- a/search/search_tests/locality_finder_test.cpp +++ b/search/search_tests/locality_finder_test.cpp @@ -34,9 +34,12 @@ void doTests2(search::LocalityFinder & finder, vector const & input, UNIT_TEST(LocalityFinder) { Index index; - m2::RectD rect; - feature::DataHeader::Version version; - TEST(index.Register("World.mwm", rect, version), ()); + pair p = index.Register("World.mwm"); + TEST(p.second, ()); + MwmSet::MwmLock & lock = p.first; + TEST(lock.IsLocked(), ()); + MwmInfo const & info = index.GetMwmInfo(lock.GetId()); + m2::RectD const & rect = info.m_limitRect; search::LocalityFinder finder(&index); finder.SetLanguage(StringUtf8Multilang::GetLangIndex("en")); @@ -57,7 +60,7 @@ UNIT_TEST(LocalityFinder) // Tets one viewport based on whole map doTests(finder, input, results); - // Test two viewport based on quaters of worl map + // Test two viewport based on quaters of world map m2::RectD rect1; rect1.setMinX(rect.minX()); rect1.setMinY(rect.minY());