From 3bdc883d6543e4e88c3492c1730d2993bad6a253 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Mon, 2 Apr 2018 01:32:57 +0300 Subject: [PATCH] Async bookmarks saving. --- map/bookmark.hpp | 6 -- map/bookmark_manager.cpp | 115 ++++++++++++++++++++----------- map/bookmark_manager.hpp | 10 +-- map/map_tests/bookmarks_test.cpp | 10 +-- 4 files changed, 85 insertions(+), 56 deletions(-) diff --git a/map/bookmark.hpp b/map/bookmark.hpp index fc765b54d2..96d200b8c0 100644 --- a/map/bookmark.hpp +++ b/map/bookmark.hpp @@ -104,11 +104,5 @@ private: kml::CategoryData m_data; }; -struct CategoryFileInfo -{ - std::string m_filePath; - std::unique_ptr m_data; -}; - std::unique_ptr LoadKMLFile(std::string const & file, bool useBinary); std::unique_ptr LoadKMLData(Reader const & reader, bool useBinary); diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 534eb51c53..969bf7361e 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -616,18 +616,22 @@ void BookmarkManager::NotifyChanges() if (!m_changesTracker.CheckChanges() && !m_firstDrapeNotification) return; - bool isBookmarks = false; + bool hasBookmarks = false; + df::GroupIDCollection categoriesToSave; for (auto groupId : m_changesTracker.GetDirtyGroupIds()) { if (IsBookmarkCategory(groupId)) { if (GetBmCategory(groupId)->IsAutoSaveEnabled()) - SaveBookmarkCategoryToFile(groupId); - isBookmarks = true; + categoriesToSave.push_back(groupId); + hasBookmarks = true; } } - if (isBookmarks) + if (hasBookmarks) + { + SaveBookmarks(categoriesToSave); SendBookmarksChanges(); + } df::DrapeEngineLockGuard lock(m_drapeEngine); if (lock) @@ -919,11 +923,6 @@ void BookmarkManager::LoadBookmarks() LoadState(); } -void BookmarkManager::MigrateAndLoadBookmarks() -{ - -} - void BookmarkManager::LoadBookmark(std::string const & filePath, bool isTemporaryFile) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); @@ -1409,7 +1408,7 @@ void BookmarkManager::CreateCategories(KMLDataCollection && dataCollection, bool { // Delete file since it will be merged. my::DeleteFileX(fileName); - SaveBookmarkCategoryToFile(groupId); + SaveBookmarks({groupId}); } } @@ -1443,79 +1442,113 @@ std::unique_ptr BookmarkManager::CollectBmGroupKMLData(BookmarkCa return kmlData; } -void BookmarkManager::SaveToKML(df::MarkGroupID groupId, Writer & writer, bool useBinary) const +bool BookmarkManager::SaveBookmarkCategory(df::MarkGroupID groupId) { - ASSERT_THREAD_CHECKER(m_threadChecker, ()); - SaveToKML(GetBmCategory(groupId), writer, useBinary); + auto collection = PrepareToSaveBookmarks({groupId}); + if (!collection || collection->empty()) + return false; + auto const & file = collection->front().first; + auto & kmlData = *collection->front().second; + return SaveKMLData(file, kmlData, migration::IsMigrationCompleted()); } -void BookmarkManager::SaveToKML(BookmarkCategory const * group, Writer & writer, bool useBinary) const +void BookmarkManager::SaveToFile(df::MarkGroupID groupId, Writer & writer, bool useBinary) const +{ + ASSERT_THREAD_CHECKER(m_threadChecker, ()); + auto * group = GetBmCategory(groupId); + auto kmlData = CollectBmGroupKMLData(group); + SaveToFile(*kmlData, writer, useBinary); +} + +void BookmarkManager::SaveToFile(kml::FileData & kmlData, Writer & writer, bool useBinary) const { - auto const kmlData = CollectBmGroupKMLData(group); if (useBinary) { - kml::binary::SerializerKml ser(*kmlData); + kml::binary::SerializerKml ser(kmlData); ser.Serialize(writer); } else { - kml::SerializerKml ser(*kmlData); + kml::SerializerKml ser(kmlData); ser.Serialize(writer); } } -bool BookmarkManager::SaveBookmarkCategoryToFile(df::MarkGroupID groupId) +std::shared_ptr BookmarkManager::PrepareToSaveBookmarks( + df::GroupIDCollection const & groupIdCollection) { - ASSERT_THREAD_CHECKER(m_threadChecker, ()); - std::string oldFile; - - auto * group = GetBmCategory(groupId); - - // Get valid file name from category name - std::string const name = RemoveInvalidSymbols(group->GetName()); - std::string file = group->GetFileName(); - bool migrated = migration::IsMigrationCompleted(); - std::string const fileExt(migrated ? kBookmarksExt : BOOKMARKS_FILE_EXTENSION); + std::string const fileDir = migrated ? GetBookmarksDirectory() : GetPlatform().SettingsDir(); + std::string const fileExt = migrated ? kBookmarksExt : BOOKMARKS_FILE_EXTENSION; if (migrated && !GetPlatform().IsFileExistsByFullPath(fileDir) && !GetPlatform().MkDirChecked(fileDir)) - return false; + return std::shared_ptr(); - if (file.empty()) + auto collection = std::make_shared(); + + for (auto const groupId : groupIdCollection) { - file = GenerateUniqueFileName(fileDir, name, fileExt); - group->SetFileName(file); - } + auto * group = GetBmCategory(groupId); - std::string const fileTmp = file + ".tmp"; + // Get valid file name from category name + std::string const name = RemoveInvalidSymbols(group->GetName()); + std::string file = group->GetFileName(); + + if (file.empty()) + { + file = GenerateUniqueFileName(fileDir, name, fileExt); + group->SetFileName(file); + } + + collection->emplace_back(file, CollectBmGroupKMLData(group)); + } + return collection; +} + +bool BookmarkManager::SaveKMLData(std::string const & file, kml::FileData & kmlData, bool useBinary) +{ + auto const fileTmp = file + ".tmp"; try { FileWriter writer(fileTmp); - SaveToKML(group, writer, migrated /* useBinary */); + SaveToFile(kmlData, writer, useBinary); // Only after successful save we replace original file my::DeleteFileX(file); VERIFY(my::RenameFileX(fileTmp, file), (fileTmp, file)); return true; } - catch (FileWriter::Exception const &exc) + catch (FileWriter::Exception const & exc) { - LOG(LDEBUG, ("KML", migrated ? " binary" : "", " serialization failure: ", exc.what(), "file", fileTmp)); + LOG(LDEBUG, ("KML serialization failure:", exc.what(), "file", fileTmp)); } catch (std::exception const & e) { - LOG(LWARNING, ("Exception while saving bookmarks:", e.what())); + LOG(LWARNING, ("Exception while saving bookmarks:", e.what(), "file", file)); } - LOG(LWARNING, ("Can't save bookmarks category", name, "to file", file)); - // remove possibly left tmp file my::DeleteFileX(fileTmp); - return false; } +void BookmarkManager::SaveBookmarks(df::GroupIDCollection const & groupIdCollection) +{ + ASSERT_THREAD_CHECKER(m_threadChecker, ()); + + auto kmlDataCollection = PrepareToSaveBookmarks(groupIdCollection); + if (!kmlDataCollection) + return; + + bool const migrated = migration::IsMigrationCompleted(); + GetPlatform().RunTask(Platform::Thread::File, [this, migrated, kmlDataCollection]() + { + for (auto const & kmlItem : *kmlDataCollection) + SaveKMLData(kmlItem.first, *kmlItem.second, migrated); + }); +} + void BookmarkManager::SetCloudEnabled(bool enabled) { m_bookmarkCloud.SetState(enabled ? Cloud::State::Enabled : Cloud::State::Disabled); diff --git a/map/bookmark_manager.hpp b/map/bookmark_manager.hpp index 47cc12d36a..65fbb2cd08 100644 --- a/map/bookmark_manager.hpp +++ b/map/bookmark_manager.hpp @@ -185,11 +185,10 @@ public: std::shared_ptr LoadBookmarksKMB(std::vector & filePaths); void LoadBookmarks(); void LoadBookmark(std::string const & filePath, bool isTemporaryFile); - void MigrateAndLoadBookmarks(); /// Uses the same file name from which was loaded, or /// creates unique file name on first save and uses it every time. - bool SaveBookmarkCategoryToFile(df::MarkGroupID groupId); + void SaveBookmarks(df::GroupIDCollection const & groupIdCollection); StaticMarkPoint & SelectionMark() { return *m_selectionMark; } StaticMarkPoint const & SelectionMark() const { return *m_selectionMark; } @@ -263,7 +262,8 @@ public: void CancelCloudRestoring(); /// These functions are public for unit tests only. You shouldn't call them from client code. - void SaveToKML(df::MarkGroupID groupId, Writer & writer, bool useBinary) const; + bool SaveBookmarkCategory(df::MarkGroupID groupId); + void SaveToFile(df::MarkGroupID groupId, Writer & writer, bool useBinary) const; void CreateCategories(KMLDataCollection && dataCollection, bool autoSave = true); static std::string RemoveInvalidSymbols(std::string const & name); static std::string GenerateUniqueFileName(std::string const & path, std::string name, std::string const & fileExt); @@ -417,7 +417,9 @@ private: void CheckAndCreateDefaultCategory(); std::unique_ptr CollectBmGroupKMLData(BookmarkCategory const * group) const; - void SaveToKML(BookmarkCategory const * group, Writer & writer, bool useBinary) const; + void SaveToFile(kml::FileData & kmlData, Writer & writer, bool useBinary) const; + std::shared_ptr PrepareToSaveBookmarks(df::GroupIDCollection const & groupIdCollection); + bool SaveKMLData(std::string const & file, kml::FileData & kmlData, bool useBinary); void OnSynchronizationStarted(Cloud::SynchronizationType type); void OnSynchronizationFinished(Cloud::SynchronizationType type, Cloud::SynchronizationResult result, diff --git a/map/map_tests/bookmarks_test.cpp b/map/map_tests/bookmarks_test.cpp index 6826cead60..80492a40b0 100644 --- a/map/map_tests/bookmarks_test.cpp +++ b/map/map_tests/bookmarks_test.cpp @@ -217,7 +217,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML) { LOG(LWARNING, ("SaveToKML (", fileName, ")")); FileWriter writer(fileName); - bmManager.SaveToKML(groupId1, writer, false /* useBinary */); + bmManager.SaveToFile(groupId1, writer, false /* useBinary */); } bmManager.GetEditSession().ClearGroup(groupId1); @@ -252,7 +252,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML) auto const groupId3 = bmManager.GetBmGroupsIdList().front(); CheckBookmarks(bmManager, groupId3); - TEST(bmManager.SaveBookmarkCategoryToFile(groupId3), ()); + TEST(bmManager.SaveBookmarkCategory(groupId3), ()); // old file shouldn't be deleted if we save bookmarks with new category name uint64_t dummy; TEST(my::GetFileSize(fileName, dummy), ()); @@ -600,11 +600,11 @@ UNIT_CLASS_TEST(Runner, BookmarkCategory_EmptyName) bm.m_point = m2::PointD(0, 0); bmManager.GetEditSession().CreateBookmark(bm, catId); - TEST(bmManager.SaveBookmarkCategoryToFile(catId), ()); + TEST(bmManager.SaveBookmarkCategory(catId), ()); bmManager.GetEditSession().SetCategoryName(catId, "xxx"); - TEST(bmManager.SaveBookmarkCategoryToFile(catId), ()); + TEST(bmManager.SaveBookmarkCategory(catId), ()); vector const arrFiles = {"Bookmarks", "xxx"}; DeleteCategoryFiles(arrFiles); @@ -659,7 +659,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames) auto const catId = groupIds.front(); auto const expectedName = "3663 and M & J Seafood Branches"; TEST_EQUAL(bmManager.GetUserMarkIds(catId).size(), 1, ()); - TEST(bmManager.SaveBookmarkCategoryToFile(catId), ()); + TEST(bmManager.SaveBookmarkCategory(catId), ()); TEST_EQUAL(bmManager.GetCategoryName(catId), expectedName, ()); // change category name to avoid merging it with the second one