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:
authorVladimir Byko-Ianko <v.bykoianko@corp.mail.ru>2017-09-12 17:59:21 +0300
committerVladimir Byko-Ianko <v.bykoianko@corp.mail.ru>2017-09-13 16:25:15 +0300
commit2e461cd29250b4cf6ee90448d49a879e471634cc (patch)
tree18c112722db87fd277a3e233d74257f7a32bf356 /storage
parent3c2db1e05c9fa91e9ed195e5b11ecb51a9b22a7a (diff)
Download diffs
Diffstat (limited to 'storage')
-rw-r--r--storage/CMakeLists.txt2
-rw-r--r--storage/diff_scheme/diff_manager.cpp127
-rw-r--r--storage/diff_scheme/diff_manager.hpp58
-rw-r--r--storage/diff_scheme/diff_scheme_checker.cpp51
-rw-r--r--storage/diff_scheme/diff_scheme_checker.hpp24
-rw-r--r--storage/diff_scheme/diff_types.hpp14
-rw-r--r--storage/index.hpp5
-rw-r--r--storage/storage.cpp240
-rw-r--r--storage/storage.hpp41
-rw-r--r--storage/storage.pro2
-rw-r--r--storage/storage_integration_tests/storage_downloading_tests.cpp4
-rw-r--r--storage/storage_integration_tests/storage_group_download_tests.cpp4
-rw-r--r--storage/storage_integration_tests/storage_http_tests.cpp6
-rw-r--r--storage/storage_integration_tests/storage_integration_tests.pro8
-rw-r--r--storage/storage_tests/storage_tests.pro4
15 files changed, 452 insertions, 138 deletions
diff --git a/storage/CMakeLists.txt b/storage/CMakeLists.txt
index b681a692a8..8e2222cd3e 100644
--- a/storage/CMakeLists.txt
+++ b/storage/CMakeLists.txt
@@ -17,6 +17,8 @@ set(
country_parent_getter.hpp
country_polygon.hpp
country_tree.hpp
+ diff_scheme/diff_manager.cpp
+ diff_scheme/diff_manager.hpp
diff_scheme/diff_scheme_checker.cpp
diff_scheme/diff_scheme_checker.hpp
diff_scheme/diff_types.hpp
diff --git a/storage/diff_scheme/diff_manager.cpp b/storage/diff_scheme/diff_manager.cpp
new file mode 100644
index 0000000000..bf64f62389
--- /dev/null
+++ b/storage/diff_scheme/diff_manager.cpp
@@ -0,0 +1,127 @@
+#include "storage/diff_scheme/diff_manager.hpp"
+#include "storage/diff_scheme/diff_scheme_checker.hpp"
+
+#include "generator/mwm_diff/diff.hpp"
+
+#include "platform/platform.hpp"
+
+#include "coding/internal/file_data.hpp"
+
+#include "base/assert.hpp"
+
+namespace storage
+{
+namespace diffs
+{
+void Manager::Load(LocalMapsInfo && info)
+{
+ LocalMapsInfo localMapsInfo = info;
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_localMapsInfo = std::move(info);
+ }
+
+ m_workerThread.Push([this, localMapsInfo]
+ {
+ NameFileInfoMap const diffs = Checker::Check(localMapsInfo);
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ m_diffs = diffs;
+ if (diffs.empty())
+ {
+ m_status = Status::NotAvailable;
+ // TODO: Log fall back to the old scheme (Downloader_DiffScheme_OnStart_fallback (Aloha)).
+ }
+ else
+ {
+ m_status = Status::Available;
+ }
+
+ auto const & observers = m_observers;
+ GetPlatform().RunOnGuiThread([observers]() mutable
+ {
+ //observers.ForEach(&Observer::OnDiffStatusReceived);
+ });
+ });
+}
+
+void Manager::ApplyDiff(ApplyDiffParams && p, std::function<void(bool const result)> const & task)
+{
+ m_workerThread.Push([this, p, task]
+ {
+ CHECK(p.m_diffFile, ());
+ CHECK(p.m_oldMwmFile, ());
+
+ auto & diffReadyPath = p.m_diffReadyPath;
+ auto & diffFile = p.m_diffFile;
+ bool result = false;
+
+ if (!my::RenameFileX(diffReadyPath, diffFile->GetPath(MapOptions::Diff)))
+ {
+ diffFile->SyncWithDisk();
+ diffFile->DeleteFromDisk(MapOptions::Diff);
+ }
+ else
+ {
+ diffFile->SyncWithDisk();
+
+ string const oldMwmPath = p.m_oldMwmFile->GetPath(MapOptions::Map);
+ string const newMwmPath = diffFile->GetPath(MapOptions::Map);
+ string const diffPath = diffFile->GetPath(MapOptions::Diff);
+ result = generator::mwm_diff::ApplyDiff(oldMwmPath, newMwmPath, diffPath);
+ diffFile->DeleteFromDisk(MapOptions::Diff);
+ }
+
+ if (!result)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_status = Status::NotAvailable;
+ // TODO: Log the diff applying error (Downloader_DiffScheme_error (Aloha)).
+ }
+
+ task(result);
+ });
+}
+
+Status Manager::GetStatus() const
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_status;
+}
+
+void Manager::SetStatus(Status status)
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_status = status;
+}
+
+FileInfo const & Manager::InfoFor(storage::TCountryId const & countryId) const
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ ASSERT(HasDiffFor(countryId), ());
+ return m_diffs.at(countryId);
+}
+
+bool Manager::HasDiffFor(storage::TCountryId const & countryId) const
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_diffs.find(countryId) != m_diffs.end();
+}
+
+bool Manager::IsPossibleToAutoupdate() const
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ if (m_status != Status::Available)
+ return false;
+
+ for (auto const & nameVersion : m_localMapsInfo.m_localMaps)
+ {
+ if (m_diffs.find(nameVersion.first) == m_diffs.end())
+ return false;
+ }
+ return true;
+}
+} // namespace diffs
+} // namespace storage
diff --git a/storage/diff_scheme/diff_manager.hpp b/storage/diff_scheme/diff_manager.hpp
new file mode 100644
index 0000000000..c6d01483cd
--- /dev/null
+++ b/storage/diff_scheme/diff_manager.hpp
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "storage/diff_scheme/diff_types.hpp"
+#include "storage/index.hpp"
+
+#include "base/observer_list.hpp"
+#include "base/thread_checker.hpp"
+#include "base/worker_thread.hpp"
+
+#include <functional>
+#include <mutex>
+#include <utility>
+
+namespace storage
+{
+namespace diffs
+{
+class Manager final
+{
+public:
+ struct ApplyDiffParams
+ {
+ string m_diffReadyPath;
+ TLocalFilePtr m_diffFile;
+ TLocalFilePtr m_oldMwmFile;
+ };
+
+ class Observer
+ {
+ public:
+ virtual ~Observer() = default;
+
+ virtual void OnDiffStatusReceived() = 0;
+ };
+
+ FileInfo const & InfoFor(storage::TCountryId const & countryId) const;
+ bool IsPossibleToAutoupdate() const;
+ bool HasDiffFor(storage::TCountryId const & countryId) const;
+
+ Status GetStatus() const;
+ void SetStatus(Status status);
+
+ void Load(LocalMapsInfo && info);
+ void ApplyDiff(ApplyDiffParams && p, std::function<void(bool const result)> const & task);
+
+ bool AddObserver(Observer & observer) { return m_observers.Add(observer); }
+ bool RemoveObserver(Observer const & observer) { return m_observers.Remove(observer); }
+
+private:
+ mutable std::mutex m_mutex;
+ Status m_status = Status::Undefined;
+ NameFileInfoMap m_diffs;
+ LocalMapsInfo m_localMapsInfo;
+ base::ObserverListUnsafe<Observer> m_observers;
+ base::WorkerThread m_workerThread;
+};
+} // namespace diffs
+} // namespace storage
diff --git a/storage/diff_scheme/diff_scheme_checker.cpp b/storage/diff_scheme/diff_scheme_checker.cpp
index 35e4f38269..e80e98e1e4 100644
--- a/storage/diff_scheme/diff_scheme_checker.cpp
+++ b/storage/diff_scheme/diff_scheme_checker.cpp
@@ -4,9 +4,10 @@
#include "platform/platform.hpp"
#include "base/logging.hpp"
-#include "base/thread.hpp"
#include <memory>
+#include <string>
+#include <unordered_map>
#include <utility>
#include "3party/jansson/myjansson.hpp"
@@ -17,7 +18,7 @@ using namespace std;
namespace
{
-using namespace diff_scheme;
+using namespace storage::diffs;
char const kMaxVersionKey[] = "max_version";
char const kMwmsKey[] = "mwms";
@@ -27,7 +28,7 @@ char const kVersionKey[] = "version";
auto const kTimeoutInSeconds = 5.0;
-string SerializeCheckerData(Checker::LocalMapsInfo const & info)
+string SerializeCheckerData(LocalMapsInfo const & info)
{
auto mwmsArrayNode = my::NewJSONArray();
for (auto const & nameAndVersion : info.m_localMaps)
@@ -45,7 +46,7 @@ string SerializeCheckerData(Checker::LocalMapsInfo const & info)
return buffer.get();
}
-NameFileInfoMap DeserializeResponse(string const & response, Checker::NameVersionMap const & nameVersionMap)
+NameFileInfoMap DeserializeResponse(string const & response, LocalMapsInfo::NameVersionMap const & nameVersionMap)
{
if (response.empty())
{
@@ -102,32 +103,26 @@ NameFileInfoMap DeserializeResponse(string const & response, Checker::NameVersio
}
} // namespace
-namespace diff_scheme
+namespace storage
{
-// static
-void Checker::Check(LocalMapsInfo const & info, Callback const & fn)
+namespace diffs
+{
+//static
+NameFileInfoMap Checker::Check(LocalMapsInfo const & info)
{
- // TODO(Vlad): Log falling back to old scheme.
if (info.m_localMaps.empty())
- {
- fn(NameFileInfoMap{});
- return;
- }
+ return {};
- threads::SimpleThread thread([info, fn] {
- platform::HttpClient request(DIFF_LIST_URL);
- string const body = SerializeCheckerData(info);
- ASSERT(!body.empty(), ());
- request.SetBodyData(body, "application/json");
- request.SetTimeout(kTimeoutInSeconds);
- NameFileInfoMap diffs;
- if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
- diffs = DeserializeResponse(request.ServerResponse(), info.m_localMaps);
-
- GetPlatform().RunOnGuiThread([fn, diffs] {
- fn(diffs);
- });
- });
- thread.detach();
+ platform::HttpClient request(DIFF_LIST_URL);
+ string const body = SerializeCheckerData(info);
+ ASSERT(!body.empty(), ());
+ request.SetBodyData(body, "application/json");
+ request.SetTimeout(kTimeoutInSeconds);
+ NameFileInfoMap diffs;
+ if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
+ diffs = DeserializeResponse(request.ServerResponse(), info.m_localMaps);
+
+ return diffs;
}
-} // namespace diff_scheme
+} // namespace diffs
+} // namespace storage
diff --git a/storage/diff_scheme/diff_scheme_checker.hpp b/storage/diff_scheme/diff_scheme_checker.hpp
index 537036faa4..a12c75b85c 100644
--- a/storage/diff_scheme/diff_scheme_checker.hpp
+++ b/storage/diff_scheme/diff_scheme_checker.hpp
@@ -2,26 +2,14 @@
#include "storage/diff_scheme/diff_types.hpp"
-#include <cstdint>
-#include <functional>
-#include <string>
-#include <unordered_map>
-
-namespace diff_scheme
+namespace storage
+{
+namespace diffs
{
class Checker final
{
public:
- using NameVersionMap = std::unordered_map<std::string, uint64_t>;
-
- struct LocalMapsInfo final
- {
- uint64_t m_currentDataVersion = 0;
- NameVersionMap m_localMaps;
- };
-
- using Callback = std::function<void(NameFileInfoMap const & diffs)>;
-
- static void Check(LocalMapsInfo const & info, Callback const & fn);
+ static NameFileInfoMap Check(LocalMapsInfo const & info);
};
-} // namespace diff_scheme
+} // namespace diffs
+} // namespace storage
diff --git a/storage/diff_scheme/diff_types.hpp b/storage/diff_scheme/diff_types.hpp
index c5c7c13030..dc3a515ee2 100644
--- a/storage/diff_scheme/diff_types.hpp
+++ b/storage/diff_scheme/diff_types.hpp
@@ -4,7 +4,9 @@
#include <string>
#include <unordered_map>
-namespace diff_scheme
+namespace storage
+{
+namespace diffs
{
enum class Status
{
@@ -21,4 +23,12 @@ struct FileInfo final
};
using NameFileInfoMap = std::unordered_map<std::string, FileInfo>;
-} // namespace diff_scheme
+
+struct LocalMapsInfo final
+{
+ using NameVersionMap = std::unordered_map<std::string, uint64_t>;
+ uint64_t m_currentDataVersion = 0;
+ NameVersionMap m_localMaps;
+};
+} // namespace diffs
+} // namespace storage
diff --git a/storage/index.hpp b/storage/index.hpp
index a441874c4f..1bf25f83d5 100644
--- a/storage/index.hpp
+++ b/storage/index.hpp
@@ -1,6 +1,9 @@
#pragma once
+#include "platform/local_country_file.hpp"
+
#include "std/set.hpp"
+#include "std/shared_ptr.hpp"
#include "std/string.hpp"
#include "std/unordered_set.hpp"
#include "std/vector.hpp"
@@ -13,6 +16,8 @@ using TCountriesVec = vector<TCountryId>;
extern const storage::TCountryId kInvalidCountryId;
+using TLocalFilePtr = shared_ptr<platform::LocalCountryFile>;
+
// @TODO(bykoianko) Check in counrtry tree if the countryId valid.
bool IsCountryIdValid(TCountryId const & countryId);
} // namespace storage
diff --git a/storage/storage.cpp b/storage/storage.cpp
index 866f29a099..bdb7530a65 100644
--- a/storage/storage.cpp
+++ b/storage/storage.cpp
@@ -36,6 +36,9 @@ namespace storage
{
namespace
{
+string const kUpdateQueueKey = "UpdateQueue";
+string const kDownloadQueueKey = "DownloadQueue";
+
uint64_t GetLocalSize(shared_ptr<LocalCountryFile> file, MapOptions opt)
{
if (!file)
@@ -224,7 +227,7 @@ void Storage::Migrate(TCountriesVec const & existedCountries)
for (auto const & smallCountry : mapping[country])
ss << (ss.str().empty() ? "" : ";") << smallCountry;
}
- settings::Set("DownloadQueue", ss.str());
+ settings::Set(kDownloadQueueKey, ss.str());
}
void Storage::Clear()
@@ -287,6 +290,7 @@ void Storage::RegisterAllLocalMaps()
i = j;
}
+ LoadDiffScheme();
RestoreDownloadQueue();
}
@@ -364,7 +368,7 @@ CountryFile const & Storage::GetCountryFile(TCountryId const & countryId) const
return CountryLeafByCountryId(countryId).GetFile();
}
-Storage::TLocalFilePtr Storage::GetLatestLocalFile(CountryFile const & countryFile) const
+TLocalFilePtr Storage::GetLatestLocalFile(CountryFile const & countryFile) const
{
ASSERT_THREAD_CHECKER(m_threadChecker, ());
@@ -383,7 +387,7 @@ Storage::TLocalFilePtr Storage::GetLatestLocalFile(CountryFile const & countryFi
return TLocalFilePtr();
}
-Storage::TLocalFilePtr Storage::GetLatestLocalFile(TCountryId const & countryId) const
+TLocalFilePtr Storage::GetLatestLocalFile(TCountryId const & countryId) const
{
ASSERT_THREAD_CHECKER(m_threadChecker, ());
@@ -447,10 +451,16 @@ void Storage::SaveDownloadQueue()
if (!m_keepDownloadingQueue)
return;
- stringstream ss;
+ ostringstream download;
+ ostringstream update;
for (auto const & item : m_queue)
+ {
+ auto & ss = item.GetInitOptions() == MapOptions::Diff ? update : download;
ss << (ss.str().empty() ? "" : ";") << item.GetCountryId();
- settings::Set("DownloadQueue", ss.str());
+ }
+
+ settings::Set(kDownloadQueueKey, download.str());
+ settings::Set(kUpdateQueueKey, update.str());
}
void Storage::RestoreDownloadQueue()
@@ -458,16 +468,20 @@ void Storage::RestoreDownloadQueue()
if (!m_keepDownloadingQueue)
return;
- string queue;
- if (!settings::Get("DownloadQueue", queue))
+ string download, update;
+ if (!settings::Get(kDownloadQueueKey, download) && !settings::Get(kUpdateQueueKey, update))
return;
- strings::SimpleTokenizer iter(queue, ";");
- while (iter)
- {
- DownloadNode(*iter);
- ++iter;
- }
+ auto parse = [this](string const & token, bool isUpdate) {
+ if (token.empty())
+ return;
+
+ for (strings::SimpleTokenizer iter(token, ";"); iter; ++iter)
+ DownloadNode(*iter, isUpdate);
+ };
+
+ parse(download, false /* isUpdate */);
+ parse(update, true /* isUpdate */);
}
void Storage::DownloadCountry(TCountryId const & countryId, MapOptions opt)
@@ -707,8 +721,6 @@ void Storage::OnMapFileDownloadFinished(bool success,
return;
}
- OnMapDownloadFinished(countryId, success, queuedCountry.GetInitOptions());
-
// Send stastics to Push Woosh.
if (success)
{
@@ -721,12 +733,7 @@ void Storage::OnMapFileDownloadFinished(bool success,
std::string(nowStr));
}
- CorrectJustDownloadedAndQueue(m_queue.begin());
- SaveDownloadQueue();
-
- m_downloader->Reset();
- NotifyStatusChangedForHierarchy(countryId);
- DownloadNextCountryFromQueue();
+ OnMapDownloadFinished(countryId, success, queuedCountry.GetInitOptions());
}
void Storage::ReportProgress(TCountryId const & countryId, MapFilesDownloader::TProgress const & p)
@@ -768,18 +775,33 @@ void Storage::OnServerListDownloaded(vector<string> const & urls)
if (m_queue.empty())
return;
- QueuedCountry const & queuedCountry = m_queue.front();
- TCountryId const & countryId = queuedCountry.GetCountryId();
- MapOptions const file = queuedCountry.GetCurrentFile();
+ QueuedCountry & queuedCountry = m_queue.front();
+ if (queuedCountry.GetInitOptions() == MapOptions::Diff)
+ {
+ using diffs::Status;
+ auto const status = m_diffManager.GetStatus();
+ switch (status)
+ {
+ case Status::Undefined:
+ m_deferredDownloads.push_back(urls);
+ return;
+ case Status::NotAvailable:
+ queuedCountry.ResetToDefaultOptions();
+ break;
+ case Status::Available:
+ break;
+ }
+ }
vector<string> const & downloadingUrls =
m_downloadingUrlsForTesting.empty() ? urls : m_downloadingUrlsForTesting;
vector<string> fileUrls;
fileUrls.reserve(downloadingUrls.size());
for (string const & url : downloadingUrls)
- fileUrls.push_back(GetFileDownloadUrl(url, countryId, file));
+ fileUrls.push_back(GetFileDownloadUrl(url, queuedCountry));
- string const filePath = GetFileDownloadPath(countryId, file);
+ string const filePath =
+ GetFileDownloadPath(queuedCountry.GetCountryId(), queuedCountry.GetCurrentFile());
m_downloader->DownloadMapFile(fileUrls, filePath, GetDownloadSize(queuedCountry),
bind(&Storage::OnMapFileDownloadFinished, this, _1, _2),
bind(&Storage::OnMapFileDownloadProgress, this, _1));
@@ -799,8 +821,35 @@ void Storage::OnMapFileDownloadProgress(MapFilesDownloader::TProgress const & pr
ReportProgressForHierarchy(m_queue.front().GetCountryId(), progress);
}
-bool Storage::RegisterDownloadedFiles(TCountryId const & countryId, MapOptions files)
+void Storage::RegisterDownloadedFiles(TCountryId const & countryId, MapOptions files,
+ DownloadedFilesProcessingFn && fn)
{
+ if (files == MapOptions::Diff)
+ {
+ diffs::Manager::ApplyDiffParams params;
+ params.m_diffFile =
+ PreparePlaceForCountryFiles(GetCurrentDataVersion(), m_dataDir, GetCountryFile(countryId));
+ params.m_diffReadyPath = GetFileDownloadPath(countryId, MapOptions::Diff);
+ params.m_oldMwmFile = GetLocalFile(countryId, m_diffManager.InfoFor(countryId).m_version);
+
+ TLocalFilePtr & diffFile = params.m_diffFile;
+
+ m_diffManager.ApplyDiff(move(params), [this, fn, diffFile] (bool const result)
+ {
+ GetPlatform().RunOnGuiThread([this, fn, diffFile, result]
+ {
+ if (result)
+ {
+ RegisterCountryFiles(diffFile);
+ }
+
+ fn(result);
+ });
+ });
+
+ return;
+ }
+
CountryFile const countryFile = GetCountryFile(countryId);
TLocalFilePtr localFile = GetLocalFile(countryId, GetCurrentDataVersion());
if (!localFile)
@@ -809,7 +858,8 @@ bool Storage::RegisterDownloadedFiles(TCountryId const & countryId, MapOptions f
{
LOG(LERROR, ("Local file data structure can't be prepared for downloaded file(", countryFile,
files, ")."));
- return false;
+ fn(false /* isSuccess */);
+ return;
}
bool ok = true;
@@ -828,33 +878,33 @@ bool Storage::RegisterDownloadedFiles(TCountryId const & countryId, MapOptions f
break;
}
}
- localFile->SyncWithDisk();
+
if (!ok)
{
localFile->DeleteFromDisk(files);
- return false;
+ fn(false);
+ return;
}
+
RegisterCountryFiles(localFile);
- return true;
+ fn(true);
}
void Storage::OnMapDownloadFinished(TCountryId const & countryId, bool success, MapOptions files)
{
+ ASSERT_THREAD_CHECKER(m_threadChecker, ());
ASSERT(m_didDownload != nullptr, ("Storage::Init wasn't called"));
ASSERT_NOT_EQUAL(MapOptions::Nothing, files,
("This method should not be called for empty files set."));
- {
- alohalytics::LogEvent(
- "$OnMapDownloadFinished",
- alohalytics::TStringMap({{"name", countryId},
- {"status", success ? "ok" : "failed"},
- {"version", strings::to_string(GetCurrentDataVersion())},
- {"option", DebugPrint(files)}}));
- GetPlatform().GetMarketingService().SendMarketingEvent(marketing::kDownloaderMapActionFinished,
- {{"action", "download"}});
- }
- success = success && RegisterDownloadedFiles(countryId, files);
+ alohalytics::LogEvent(
+ "$OnMapDownloadFinished",
+ alohalytics::TStringMap({{"name", countryId},
+ {"status", success ? "ok" : "failed"},
+ {"version", strings::to_string(GetCurrentDataVersion())},
+ {"option", DebugPrint(files)}}));
+ GetPlatform().GetMarketingService().SendMarketingEvent(marketing::kDownloaderMapActionFinished,
+ {{"action", "download"}});
if (!success)
{
@@ -862,25 +912,49 @@ void Storage::OnMapDownloadFinished(TCountryId const & countryId, bool success,
return;
}
- TLocalFilePtr localFile = GetLocalFile(countryId, GetCurrentDataVersion());
- ASSERT(localFile, ());
- DeleteCountryIndexes(*localFile);
- m_didDownload(countryId, localFile);
+ RegisterDownloadedFiles(countryId, files, [this, countryId](bool isSuccess)
+ {
+ ASSERT_THREAD_CHECKER(m_threadChecker, ());
+ if (!isSuccess)
+ {
+ m_failedCountries.insert(countryId);
+ return;
+ }
+
+ TLocalFilePtr localFile = GetLocalFile(countryId, GetCurrentDataVersion());
+ ASSERT(localFile, ());
+ DeleteCountryIndexes(*localFile);
+ m_didDownload(countryId, localFile);
+
+ CorrectJustDownloadedAndQueue(m_queue.begin());
+ SaveDownloadQueue();
+
+ m_downloader->Reset();
+ NotifyStatusChangedForHierarchy(countryId);
+ DownloadNextCountryFromQueue();
+ });
}
-string Storage::GetFileDownloadUrl(string const & baseUrl, TCountryId const & countryId,
- MapOptions file) const
+string Storage::GetFileDownloadUrl(string const & baseUrl,
+ QueuedCountry const & queuedCountry) const
{
+ auto const & countryId = queuedCountry.GetCountryId();
CountryFile const & countryFile = GetCountryFile(countryId);
- string const fileName = GetFileName(countryFile.GetName(), file, GetCurrentDataVersion());
- return GetFileDownloadUrl(baseUrl, fileName);
-}
+ auto const currentFileOpt = queuedCountry.GetCurrentFile();
+ string const fileName =
+ GetFileName(countryFile.GetName(), currentFileOpt, GetCurrentDataVersion());
-string Storage::GetFileDownloadUrl(string const & baseUrl, string const & fName) const
-{
- return baseUrl + OMIM_OS_NAME "/" + strings::to_string(GetCurrentDataVersion()) + "/" +
- UrlEncode(fName);
+ ostringstream url;
+ url << baseUrl;
+ string const currentVersion = strings::to_string(GetCurrentDataVersion());
+ if (currentFileOpt == MapOptions::Diff)
+ url << "diffs/" << currentVersion << "/" << strings::to_string(m_diffManager.InfoFor(countryId).m_version);
+ else
+ url << OMIM_OS_NAME "/" << currentVersion;
+
+ url << "/" << UrlEncode(fileName);
+ return url.str();
}
TCountryId Storage::FindCountryIdByFile(string const & name) const
@@ -999,7 +1073,7 @@ void Storage::SetLocaleForTesting(string const & jsonBuffer, string const & loca
m_countryNameGetter.SetLocaleForTesting(jsonBuffer, locale);
}
-Storage::TLocalFilePtr Storage::GetLocalFile(TCountryId const & countryId, int64_t version) const
+TLocalFilePtr Storage::GetLocalFile(TCountryId const & countryId, int64_t version) const
{
auto const it = m_localFiles.find(countryId);
if (it == m_localFiles.end() || it->second.empty())
@@ -1129,7 +1203,11 @@ bool Storage::DeleteCountryFilesFromDownloader(TCountryId const & countryId, Map
uint64_t Storage::GetDownloadSize(QueuedCountry const & queuedCountry) const
{
- CountryFile const & file = GetCountryFile(queuedCountry.GetCountryId());
+ TCountryId const & countryId = queuedCountry.GetCountryId();
+ if (queuedCountry.GetInitOptions() == MapOptions::Diff)
+ return m_diffManager.InfoFor(countryId).m_size;
+
+ CountryFile const & file = GetCountryFile(countryId);
return GetRemoteSize(file, queuedCountry.GetCurrentFile(), GetCurrentDataVersion());
}
@@ -1265,7 +1343,7 @@ bool Storage::HasLatestVersion(TCountryId const & countryId) const
return CountryStatusEx(countryId) == Status::EOnDisk;
}
-void Storage::DownloadNode(TCountryId const & countryId)
+void Storage::DownloadNode(TCountryId const & countryId, bool isUpdate /* = false */)
{
ASSERT_THREAD_CHECKER(m_threadChecker, ());
@@ -1277,10 +1355,11 @@ void Storage::DownloadNode(TCountryId const & countryId)
if (GetNodeStatus(*node).status == NodeStatus::OnDisk)
return;
- auto downloadAction = [this](TCountryTreeNode const & descendantNode) {
+ auto downloadAction = [this, isUpdate](TCountryTreeNode const & descendantNode) {
if (descendantNode.ChildrenCount() == 0 &&
GetNodeStatus(descendantNode).status != NodeStatus::OnDisk)
- this->DownloadCountry(descendantNode.Value().Name(), MapOptions::MapWithCarRouting);
+ this->DownloadCountry(descendantNode.Value().Name(),
+ isUpdate ? MapOptions::Diff : MapOptions::MapWithCarRouting);
};
node->ForEachInSubtree(downloadAction);
@@ -1329,6 +1408,38 @@ void Storage::CalMaxMwmSizeBytes()
});
}
+void Storage::LoadDiffScheme()
+{
+ ASSERT_THREAD_CHECKER(m_threadChecker, ());
+ diffs::LocalMapsInfo localMapsInfo;
+ auto const currentVersion = GetCurrentDataVersion();
+ localMapsInfo.m_currentDataVersion = currentVersion;
+ vector<TLocalFilePtr> localMaps;
+ GetLocalMaps(localMaps);
+ for (auto const & map : localMaps)
+ {
+ auto const mapVersion = map->GetVersion();
+ if (mapVersion != currentVersion && mapVersion > 0)
+ localMapsInfo.m_localMaps.emplace(map->GetCountryName(), mapVersion);
+ }
+ m_diffManager.AddObserver(*this);
+ m_diffManager.Load(move(localMapsInfo));
+}
+
+bool Storage::IsPossibleToAutoupdate() const
+{
+ ASSERT_THREAD_CHECKER(m_threadChecker, ());
+ return m_diffManager.IsPossibleToAutoupdate();
+}
+
+void Storage::OnDiffStatusReceived()
+{
+ for (auto const & urls : m_deferredDownloads)
+ OnServerListDownloaded(urls);
+
+ m_deferredDownloads.clear();
+}
+
StatusAndError Storage::GetNodeStatusInfo(
TCountryTreeNode const & node, vector<pair<TCountryId, NodeStatus>> & disputedTerritories,
bool isDisputedTerritoriesCounted) const
@@ -1451,7 +1562,7 @@ void Storage::GetNodeAttrs(TCountryId const & countryId, NodeAttrs & nodeAttrs)
}
// Local mwm information.
- Storage::TLocalFilePtr const localFile = GetLatestLocalFile(countryId);
+ TLocalFilePtr const localFile = GetLatestLocalFile(countryId);
if (localFile == nullptr)
return;
@@ -1546,7 +1657,7 @@ void Storage::UpdateNode(TCountryId const & countryId)
{
ForEachInSubtree(countryId, [this](TCountryId const & descendantId, bool groupNode) {
if (!groupNode && m_localFiles.find(descendantId) != m_localFiles.end())
- this->DownloadNode(descendantId);
+ this->DownloadNode(descendantId, true /* isUpdate */);
});
}
@@ -1570,7 +1681,10 @@ void Storage::RetryDownloadNode(TCountryId const & countryId)
{
ForEachInSubtree(countryId, [this](TCountryId const & descendantId, bool groupNode) {
if (!groupNode && m_failedCountries.count(descendantId) != 0)
- DownloadNode(descendantId);
+ {
+ bool const isUpdateRequest = m_diffManager.HasDiffFor(descendantId);
+ DownloadNode(descendantId, isUpdateRequest);
+ }
});
}
diff --git a/storage/storage.hpp b/storage/storage.hpp
index d93f0a820b..54d5539e7e 100644
--- a/storage/storage.hpp
+++ b/storage/storage.hpp
@@ -3,18 +3,21 @@
#include "storage/country.hpp"
#include "storage/country_name_getter.hpp"
#include "storage/country_tree.hpp"
+#include "storage/diff_scheme/diff_manager.hpp"
#include "storage/downloading_policy.hpp"
-#include "storage/storage_defines.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 "platform/local_country_file.hpp"
#include "base/deferred_task.hpp"
#include "base/thread_checker.hpp"
+#include "base/worker_thread.hpp"
+#include <future>
#include "std/function.hpp"
#include "std/list.hpp"
#include "std/shared_ptr.hpp"
@@ -134,11 +137,10 @@ struct NodeStatuses
};
/// This class is used for downloading, updating and deleting maps.
-class Storage
+class Storage : public diffs::Manager::Observer
{
public:
struct StatusCallback;
- using TLocalFilePtr = shared_ptr<platform::LocalCountryFile>;
using TUpdateCallback = function<void(storage::TCountryId const &, TLocalFilePtr const)>;
using TDeleteCallback = function<bool(storage::TCountryId const &, TLocalFilePtr const)>;
using TChangeCountryFunction = function<void(TCountryId const &)>;
@@ -244,6 +246,10 @@ private:
ThreadChecker m_threadChecker;
+ diffs::Manager m_diffManager;
+
+ vector<vector<string>> m_deferredDownloads;
+
void DownloadNextCountryFromQueue();
void LoadCountriesFile(string const & pathToCountriesFile, string const & dataDir,
@@ -265,7 +271,10 @@ private:
/// during the downloading process.
void OnMapFileDownloadProgress(MapFilesDownloader::TProgress const & progress);
- bool RegisterDownloadedFiles(TCountryId const & countryId, MapOptions files);
+ using DownloadedFilesProcessingFn = function<void(bool isSuccess)>;
+ void RegisterDownloadedFiles(TCountryId const & countryId, MapOptions files,
+ DownloadedFilesProcessingFn && fn);
+
void OnMapDownloadFinished(TCountryId const & countryId, bool success, MapOptions files);
/// Initiates downloading of the next file from the queue.
@@ -391,10 +400,10 @@ public:
string GetNodeLocalName(TCountryId const & countryId) const { return m_countryNameGetter(countryId); }
- /// \brief Downloads one node (expandable or not) by countryId.
- /// If node is expandable downloads all children (grandchildren) by the node
- /// until they havn't been downloaded before. Update downloaded mwm if it's necessary.
- void DownloadNode(TCountryId const & countryId);
+ /// \brief Downloads/update one node (expandable or not) by countryId.
+ /// If node is expandable downloads/update all children (grandchildren) by the node
+ /// until they haven't been downloaded before.
+ void DownloadNode(TCountryId const & countryId, bool isUpdate = false);
/// \brief Delete node with all children (expandable or not).
void DeleteNode(TCountryId const & countryId);
@@ -525,12 +534,8 @@ public:
TCountryId GetCurrentDownloadingCountryId() const;
void EnableKeepDownloadingQueue(bool enable) {m_keepDownloadingQueue = enable;}
-
- /// get download url by countryId & options(first search file name by countryId, then format url)
- string GetFileDownloadUrl(string const & baseUrl, TCountryId const & countryId, MapOptions file) const;
-
- /// get download url by base url & file name
- string GetFileDownloadUrl(string const & baseUrl, string const & fName) const;
+ /// get download url by base url & queued country
+ string GetFileDownloadUrl(string const & baseUrl, QueuedCountry const & queuedCountry) const;
/// @param[out] res Populated with oudated countries.
void GetOutdatedCountries(vector<Country const *> & countries) const;
@@ -547,6 +552,10 @@ public:
void SetDownloadingUrlsForTesting(vector<string> const & downloadingUrls);
void SetLocaleForTesting(string const & jsonBuffer, string const & locale);
+ /// Returns true if the diff scheme is available and all local outdated maps can be updated via
+ /// diffs.
+ bool IsPossibleToAutoupdate() const;
+
private:
friend struct UnitClass_StorageTest_DeleteCountry;
friend struct UnitClass_TwoComponentStorageTest_DeleteCountry;
@@ -645,6 +654,10 @@ private:
bool IsDisputed(TCountryTreeNode const & node) const;
void CalMaxMwmSizeBytes();
+
+ void LoadDiffScheme();
+
+ void OnDiffStatusReceived() override;
};
void GetQueuedCountries(Storage::TQueue const & queue, TCountriesSet & resultCountries);
diff --git a/storage/storage.pro b/storage/storage.pro
index 81860a7b2c..282c6db6ca 100644
--- a/storage/storage.pro
+++ b/storage/storage.pro
@@ -18,6 +18,7 @@ HEADERS += \
country_parent_getter.hpp \
country_polygon.hpp \
country_tree.hpp \
+ diff_scheme/diff_manager.hpp \
diff_scheme/diff_scheme_checker.hpp \
diff_scheme/diff_types.hpp \
downloader_search_params.hpp \
@@ -36,6 +37,7 @@ SOURCES += \
country_info_getter.cpp \
country_name_getter.cpp \
country_parent_getter.cpp \
+ diff_scheme/diff_manager.cpp \
diff_scheme/diff_scheme_checker.cpp \
downloading_policy.cpp \
http_map_files_downloader.cpp \
diff --git a/storage/storage_integration_tests/storage_downloading_tests.cpp b/storage/storage_integration_tests/storage_downloading_tests.cpp
index bf9747663f..1a05e05225 100644
--- a/storage/storage_integration_tests/storage_downloading_tests.cpp
+++ b/storage/storage_integration_tests/storage_downloading_tests.cpp
@@ -29,7 +29,7 @@ string const kCountryId = "Angola";
class InterruptException : public exception {};
-void Update(TCountryId const &, storage::Storage::TLocalFilePtr const localCountryFile)
+void Update(TCountryId const &, storage::TLocalFilePtr const localCountryFile)
{
TEST_EQUAL(localCountryFile->GetCountryName(), kCountryId, ());
}
@@ -44,7 +44,7 @@ void ChangeCountry(Storage & storage, TCountryId const & countryId)
void InitStorage(Storage & storage, Storage::TProgressFunction const & onProgressFn)
{
- storage.Init(Update, [](TCountryId const &, storage::Storage::TLocalFilePtr const){return false;});
+ storage.Init(Update, [](TCountryId const &, storage::TLocalFilePtr const){return false;});
storage.RegisterAllLocalMaps();
storage.Subscribe(bind(&ChangeCountry, ref(storage), _1), onProgressFn);
storage.SetDownloadingUrlsForTesting({kTestWebServer});
diff --git a/storage/storage_integration_tests/storage_group_download_tests.cpp b/storage/storage_integration_tests/storage_group_download_tests.cpp
index 884eead739..b7fc24aa65 100644
--- a/storage/storage_integration_tests/storage_group_download_tests.cpp
+++ b/storage/storage_integration_tests/storage_group_download_tests.cpp
@@ -262,13 +262,13 @@ void TestDownloadDelete(bool downloadOneByOne, bool deleteOneByOne)
TEST(version::IsSingleMwm(storage.GetCurrentDataVersion()), ());
string const version = strings::to_string(storage.GetCurrentDataVersion());
- auto onUpdatedFn = [&](TCountryId const &, storage::Storage::TLocalFilePtr const localCountryFile)
+ auto onUpdatedFn = [&](TCountryId const &, storage::TLocalFilePtr const localCountryFile)
{
TCountryId const countryId = localCountryFile->GetCountryName();
TEST(kLeafCountriesIds.find(countryId) != kLeafCountriesIds.end(), ());
};
- storage.Init(onUpdatedFn, [](TCountryId const &, storage::Storage::TLocalFilePtr const){return false;});
+ storage.Init(onUpdatedFn, [](TCountryId const &, storage::TLocalFilePtr const){return false;});
storage.RegisterAllLocalMaps();
storage.SetDownloadingUrlsForTesting({kTestWebServer});
diff --git a/storage/storage_integration_tests/storage_http_tests.cpp b/storage/storage_integration_tests/storage_http_tests.cpp
index 0e15bc889a..6419113ff7 100644
--- a/storage/storage_integration_tests/storage_http_tests.cpp
+++ b/storage/storage_integration_tests/storage_http_tests.cpp
@@ -29,12 +29,12 @@ string const kDisputedCountryId2 = "Crimea";
string const kDisputedCountryId3 = "Campo de Hielo Sur";
string const kUndisputedCountryId = "Argentina_Buenos Aires_North";
-void Update(TCountryId const &, Storage::TLocalFilePtr const localCountryFile)
+void Update(TCountryId const &, TLocalFilePtr const localCountryFile)
{
TEST_EQUAL(localCountryFile->GetCountryName(), kCountryId, ());
}
-void UpdateWithoutChecks(TCountryId const &, Storage::TLocalFilePtr const /* localCountryFile */)
+void UpdateWithoutChecks(TCountryId const &, TLocalFilePtr const /* localCountryFile */)
{
}
@@ -70,7 +70,7 @@ void InitStorage(Storage & storage, Storage::TUpdateCallback const & didDownload
}
};
- storage.Init(didDownload, [](TCountryId const &, Storage::TLocalFilePtr const){return false;});
+ storage.Init(didDownload, [](TCountryId const &, TLocalFilePtr const){return false;});
storage.RegisterAllLocalMaps();
storage.Subscribe(changeCountryFunction, progress);
storage.SetDownloadingUrlsForTesting({kTestWebServer});
diff --git a/storage/storage_integration_tests/storage_integration_tests.pro b/storage/storage_integration_tests/storage_integration_tests.pro
index 98381c425a..153b3cda08 100644
--- a/storage/storage_integration_tests/storage_integration_tests.pro
+++ b/storage/storage_integration_tests/storage_integration_tests.pro
@@ -6,10 +6,10 @@ CONFIG -= app_bundle
TEMPLATE = app
ROOT_DIR = ../..
-DEPENDENCIES = map drape_frontend routing search storage tracking traffic routing_common ugc indexer drape \
- partners_api local_ads platform_tests_support platform editor opening_hours geometry \
- coding base freetype expat jansson protobuf osrm stats_client \
- minizip succinct pugixml oauthcpp stb_image sdf_image icu agg
+DEPENDENCIES = map drape_frontend routing search storage tracking traffic routing_common ugc \
+ indexer drape partners_api local_ads platform_tests_support platform editor \
+ mwm_diff opening_hours geometry coding base freetype expat jansson protobuf osrm \
+ stats_client minizip succinct pugixml oauthcpp stb_image sdf_image icu agg
include($$ROOT_DIR/common.pri)
diff --git a/storage/storage_tests/storage_tests.pro b/storage/storage_tests/storage_tests.pro
index 970261c2d3..fd717a1993 100644
--- a/storage/storage_tests/storage_tests.pro
+++ b/storage/storage_tests/storage_tests.pro
@@ -11,8 +11,8 @@ macx*|win32*|linux* {
DEPENDENCIES = generator_tests_support generator
}
-DEPENDENCIES *= drape_frontend map routing traffic routing_common \
- search storage indexer drape platform_tests_support platform editor opening_hours geometry \
+DEPENDENCIES *= drape_frontend map routing traffic routing_common search storage indexer drape \
+ platform_tests_support platform editor mwm_diff opening_hours geometry \
coding base freetype expat jansson tess2 protobuf osrm stats_client \
minizip succinct pugixml oauthcpp stb_image sdf_image icu agg