Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
68
libs/storage/diff_scheme/apply_diff.cpp
Normal file
68
libs/storage/diff_scheme/apply_diff.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#include "storage/diff_scheme/apply_diff.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "coding/internal/file_data.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/cancellable.hpp"
|
||||
|
||||
namespace storage
|
||||
{
|
||||
namespace diffs
|
||||
{
|
||||
void ApplyDiff(ApplyDiffParams && p, base::Cancellable const & cancellable, OnDiffApplicationFinished const & task)
|
||||
{
|
||||
using namespace generator::mwm_diff;
|
||||
|
||||
GetPlatform().RunTask(Platform::Thread::File, [p = std::move(p), &cancellable, task]
|
||||
{
|
||||
CHECK(p.m_diffFile, ());
|
||||
CHECK(p.m_oldMwmFile, ());
|
||||
|
||||
auto & diffReadyPath = p.m_diffReadyPath;
|
||||
auto & diffFile = p.m_diffFile;
|
||||
auto const diffPath = diffFile->GetPath(MapFileType::Diff);
|
||||
auto result = DiffApplicationResult::Failed;
|
||||
|
||||
diffFile->SyncWithDisk();
|
||||
if (!diffFile->OnDisk(MapFileType::Diff))
|
||||
{
|
||||
base::RenameFileX(diffReadyPath, diffPath);
|
||||
diffFile->SyncWithDisk();
|
||||
}
|
||||
|
||||
auto const isFilePrepared = diffFile->OnDisk(MapFileType::Diff);
|
||||
|
||||
if (isFilePrepared)
|
||||
{
|
||||
std::string const oldMwmPath = p.m_oldMwmFile->GetPath(MapFileType::Map);
|
||||
std::string const newMwmPath = diffFile->GetPath(MapFileType::Map);
|
||||
std::string const diffApplyingInProgressPath = newMwmPath + DIFF_APPLYING_FILE_EXTENSION;
|
||||
|
||||
result = generator::mwm_diff::ApplyDiff(oldMwmPath, diffApplyingInProgressPath, diffPath, cancellable);
|
||||
if (result == DiffApplicationResult::Ok && !base::RenameFileX(diffApplyingInProgressPath, newMwmPath))
|
||||
result = DiffApplicationResult::Failed;
|
||||
|
||||
Platform::RemoveFileIfExists(diffApplyingInProgressPath);
|
||||
|
||||
if (result != DiffApplicationResult::Ok)
|
||||
Platform::RemoveFileIfExists(newMwmPath);
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case DiffApplicationResult::Ok: diffFile->DeleteFromDisk(MapFileType::Diff); break;
|
||||
case DiffApplicationResult::Cancelled:
|
||||
// The diff file will be deleted by storage.
|
||||
// Another way would be to leave it on disk but all consequences
|
||||
// of interacting with storage are much harder to be taken into account that way.
|
||||
break;
|
||||
case DiffApplicationResult::Failed: diffFile->DeleteFromDisk(MapFileType::Diff); break;
|
||||
}
|
||||
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [task, result]() { task(result); });
|
||||
});
|
||||
}
|
||||
} // namespace diffs
|
||||
} // namespace storage
|
||||
29
libs/storage/diff_scheme/apply_diff.hpp
Normal file
29
libs/storage/diff_scheme/apply_diff.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "mwm_diff/diff.hpp"
|
||||
|
||||
#include "storage/storage_defines.hpp"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace base
|
||||
{
|
||||
class Cancellable;
|
||||
}
|
||||
|
||||
namespace storage
|
||||
{
|
||||
namespace diffs
|
||||
{
|
||||
struct ApplyDiffParams
|
||||
{
|
||||
std::string m_diffReadyPath;
|
||||
LocalFilePtr m_diffFile;
|
||||
LocalFilePtr m_oldMwmFile;
|
||||
};
|
||||
|
||||
using OnDiffApplicationFinished = std::function<void(generator::mwm_diff::DiffApplicationResult)>;
|
||||
|
||||
void ApplyDiff(ApplyDiffParams && p, base::Cancellable const & cancellable, OnDiffApplicationFinished const & task);
|
||||
} // namespace diffs
|
||||
} // namespace storage
|
||||
148
libs/storage/diff_scheme/diff_scheme_loader.cpp
Normal file
148
libs/storage/diff_scheme/diff_scheme_loader.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#include "storage/diff_scheme/diff_scheme_loader.hpp"
|
||||
|
||||
#include "platform/http_client.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "cppjansson/cppjansson.hpp"
|
||||
|
||||
#include "private.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace storage::diffs;
|
||||
|
||||
char constexpr kMaxVersionKey[] = "max_version";
|
||||
char constexpr kMwmsKey[] = "mwms";
|
||||
char constexpr kNameKey[] = "name";
|
||||
char constexpr kSizeKey[] = "size";
|
||||
char constexpr kVersionKey[] = "version";
|
||||
|
||||
auto constexpr kTimeoutInSeconds = 5.0;
|
||||
|
||||
string SerializeCheckerData(LocalMapsInfo const & info)
|
||||
{
|
||||
auto mwmsArrayNode = base::NewJSONArray();
|
||||
for (auto const & nameAndVersion : info.m_localMaps)
|
||||
{
|
||||
auto node = base::NewJSONObject();
|
||||
ToJSONObject(*node, kNameKey, nameAndVersion.first);
|
||||
ToJSONObject(*node, kVersionKey, nameAndVersion.second);
|
||||
json_array_append_new(mwmsArrayNode.get(), node.release());
|
||||
}
|
||||
|
||||
auto const root = base::NewJSONObject();
|
||||
json_object_set_new(root.get(), kMwmsKey, mwmsArrayNode.release());
|
||||
ToJSONObject(*root, kMaxVersionKey, info.m_currentDataVersion);
|
||||
unique_ptr<char, JSONFreeDeleter> buffer(json_dumps(root.get(), JSON_COMPACT));
|
||||
return buffer.get();
|
||||
}
|
||||
|
||||
NameDiffInfoMap DeserializeResponse(string const & response, LocalMapsInfo::NameVersionMap const & nameVersionMap)
|
||||
{
|
||||
if (response.empty())
|
||||
{
|
||||
LOG(LERROR, ("Diff response shouldn't be empty."));
|
||||
return {};
|
||||
}
|
||||
|
||||
base::Json const json(response.c_str());
|
||||
if (json.get() == nullptr)
|
||||
return {};
|
||||
|
||||
auto const root = json_object_get(json.get(), kMwmsKey);
|
||||
if (root == nullptr || !json_is_array(root))
|
||||
return {};
|
||||
|
||||
auto const count = json_array_size(root);
|
||||
if (count == 0 || count != nameVersionMap.size())
|
||||
{
|
||||
LOG(LERROR, ("Diff list size in response must be equal to mwm list size in request."));
|
||||
return {};
|
||||
}
|
||||
|
||||
NameDiffInfoMap diffs;
|
||||
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
auto const node = json_array_get(root, i);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
LOG(LERROR, ("Incorrect server response."));
|
||||
return {};
|
||||
}
|
||||
|
||||
string name;
|
||||
FromJSONObject(node, kNameKey, name);
|
||||
int64_t size;
|
||||
FromJSONObject(node, kSizeKey, size);
|
||||
// Invalid size. The diff is not available.
|
||||
if (size < 0)
|
||||
continue;
|
||||
|
||||
if (nameVersionMap.find(name) == nameVersionMap.end())
|
||||
{
|
||||
LOG(LERROR, ("Incorrect country name in response:", name));
|
||||
return {};
|
||||
}
|
||||
|
||||
DiffInfo info(size, nameVersionMap.at(name));
|
||||
diffs.emplace(std::move(name), std::move(info));
|
||||
}
|
||||
|
||||
return diffs;
|
||||
}
|
||||
|
||||
NameDiffInfoMap Load(LocalMapsInfo const & info)
|
||||
{
|
||||
if (info.m_localMaps.empty() || DIFF_LIST_URL[0] == 0)
|
||||
return {};
|
||||
|
||||
platform::HttpClient request(DIFF_LIST_URL);
|
||||
string const body = SerializeCheckerData(info);
|
||||
ASSERT(!body.empty(), ());
|
||||
request.SetBodyData(body, "application/json");
|
||||
request.SetTimeout(kTimeoutInSeconds);
|
||||
NameDiffInfoMap diffs;
|
||||
if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
|
||||
{
|
||||
diffs = DeserializeResponse(request.ServerResponse(), info.m_localMaps);
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream ost;
|
||||
ost << "Request to diffs server failed. Code = " << request.ErrorCode()
|
||||
<< ", redirection = " << request.WasRedirected();
|
||||
LOG(LINFO, (ost.str()));
|
||||
}
|
||||
|
||||
return diffs;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace storage
|
||||
{
|
||||
namespace diffs
|
||||
{
|
||||
// static
|
||||
void Loader::Load(LocalMapsInfo && info, DiffsReceivedCallback && callback)
|
||||
{
|
||||
GetPlatform().RunTask(Platform::Thread::Network, [info = std::move(info), callback = std::move(callback)]()
|
||||
{
|
||||
auto result = ::Load(info);
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [result = std::move(result), callback = std::move(callback)]() mutable
|
||||
{ callback(std::move(result)); });
|
||||
});
|
||||
}
|
||||
} // namespace diffs
|
||||
} // namespace storage
|
||||
30
libs/storage/diff_scheme/diff_scheme_loader.hpp
Normal file
30
libs/storage/diff_scheme/diff_scheme_loader.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "storage/diff_scheme/diff_types.hpp"
|
||||
#include "storage/storage_defines.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
namespace diffs
|
||||
{
|
||||
struct LocalMapsInfo final
|
||||
{
|
||||
using NameVersionMap = std::unordered_map<storage::CountryId, uint64_t>;
|
||||
|
||||
uint64_t m_currentDataVersion = 0;
|
||||
NameVersionMap m_localMaps;
|
||||
};
|
||||
|
||||
using DiffsReceivedCallback = std::function<void(diffs::NameDiffInfoMap && diffs)>;
|
||||
|
||||
class Loader final
|
||||
{
|
||||
public:
|
||||
static void Load(LocalMapsInfo && info, DiffsReceivedCallback && callback);
|
||||
};
|
||||
} // namespace diffs
|
||||
} // namespace storage
|
||||
31
libs/storage/diff_scheme/diff_types.hpp
Normal file
31
libs/storage/diff_scheme/diff_types.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "storage/storage_defines.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
namespace diffs
|
||||
{
|
||||
// Status of the diffs data source as a whole.
|
||||
enum class Status
|
||||
{
|
||||
NotAvailable,
|
||||
Available
|
||||
};
|
||||
|
||||
struct DiffInfo final
|
||||
{
|
||||
DiffInfo(uint64_t size, uint64_t version) : m_size(size), m_version(version) {}
|
||||
|
||||
uint64_t m_size;
|
||||
uint64_t m_version;
|
||||
bool m_isApplied = false;
|
||||
};
|
||||
|
||||
using NameDiffInfoMap = std::unordered_map<storage::CountryId, DiffInfo>;
|
||||
} // namespace diffs
|
||||
} // namespace storage
|
||||
107
libs/storage/diff_scheme/diffs_data_source.cpp
Normal file
107
libs/storage/diff_scheme/diffs_data_source.cpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#include "storage/diff_scheme/diffs_data_source.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace
|
||||
{
|
||||
bool IsDiffsAvailable(storage::diffs::NameDiffInfoMap const & diffs)
|
||||
{
|
||||
return std::any_of(diffs.cbegin(), diffs.cend(), [](auto const & d) { return d.second.m_isApplied == false; });
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace storage
|
||||
{
|
||||
namespace diffs
|
||||
{
|
||||
void DiffsDataSource::SetDiffInfo(NameDiffInfoMap && info)
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
if (info.empty())
|
||||
{
|
||||
m_status = Status::NotAvailable;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_diffs = std::move(info);
|
||||
m_status = Status::Available;
|
||||
}
|
||||
}
|
||||
|
||||
Status DiffsDataSource::GetStatus() const
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
return m_status;
|
||||
}
|
||||
|
||||
bool DiffsDataSource::SizeFor(storage::CountryId const & countryId, uint64_t & size) const
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
if (m_status != Status::Available)
|
||||
return false;
|
||||
|
||||
auto const it = m_diffs.find(countryId);
|
||||
if (it == m_diffs.cend())
|
||||
return false;
|
||||
|
||||
size = it->second.m_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiffsDataSource::SizeToDownloadFor(storage::CountryId const & countryId, uint64_t & size) const
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
return WithNotAppliedDiff(countryId, [&size](DiffInfo const & info) { size = info.m_size; });
|
||||
}
|
||||
|
||||
bool DiffsDataSource::VersionFor(storage::CountryId const & countryId, uint64_t & v) const
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
return WithNotAppliedDiff(countryId, [&v](DiffInfo const & info) { v = info.m_version; });
|
||||
}
|
||||
|
||||
bool DiffsDataSource::HasDiffFor(storage::CountryId const & countryId) const
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
return WithNotAppliedDiff(countryId, [](DiffInfo const &) {});
|
||||
}
|
||||
|
||||
void DiffsDataSource::MarkAsApplied(storage::CountryId const & countryId)
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
auto it = m_diffs.find(countryId);
|
||||
if (it == m_diffs.end())
|
||||
return;
|
||||
|
||||
it->second.m_isApplied = true;
|
||||
|
||||
if (!IsDiffsAvailable(m_diffs))
|
||||
m_status = Status::NotAvailable;
|
||||
}
|
||||
|
||||
void DiffsDataSource::RemoveDiffForCountry(storage::CountryId const & countryId)
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
m_diffs.erase(countryId);
|
||||
|
||||
if (m_diffs.empty() || !IsDiffsAvailable(m_diffs))
|
||||
m_status = Status::NotAvailable;
|
||||
}
|
||||
|
||||
void DiffsDataSource::AbortDiffScheme()
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_threadChecker, ());
|
||||
|
||||
m_status = Status::NotAvailable;
|
||||
m_diffs.clear();
|
||||
}
|
||||
} // namespace diffs
|
||||
} // namespace storage
|
||||
65
libs/storage/diff_scheme/diffs_data_source.hpp
Normal file
65
libs/storage/diff_scheme/diffs_data_source.hpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include "storage/diff_scheme/diff_types.hpp"
|
||||
#include "storage/storage_defines.hpp"
|
||||
|
||||
#include "base/thread_checker.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
namespace diffs
|
||||
{
|
||||
class DiffsDataSource;
|
||||
using DiffsSourcePtr = std::shared_ptr<diffs::DiffsDataSource>;
|
||||
|
||||
class DiffsDataSource final
|
||||
{
|
||||
public:
|
||||
void SetDiffInfo(NameDiffInfoMap && info);
|
||||
// If the diff is available, sets |size| to its size and returns true.
|
||||
// Otherwise, returns false.
|
||||
bool SizeFor(storage::CountryId const & countryId, uint64_t & size) const;
|
||||
|
||||
// Sets |size| to how many bytes are left for the diff to be downloaded for |countryId|
|
||||
// or 0 if there is no diff available or it has already been downloaded.
|
||||
// This method may overestimate because it does not account for the possibility
|
||||
// of resuming an old download, i.e. the return value is either 0 or the diff size.
|
||||
// Returns true iff the diff is available.
|
||||
bool SizeToDownloadFor(storage::CountryId const & countryId, uint64_t & size) const;
|
||||
|
||||
bool VersionFor(storage::CountryId const & countryId, uint64_t & version) const;
|
||||
|
||||
// Checks whether the diff for |countryId| is available for download or
|
||||
// has been downloaded.
|
||||
bool HasDiffFor(storage::CountryId const & countryId) const;
|
||||
|
||||
void MarkAsApplied(storage::CountryId const & countryId);
|
||||
void RemoveDiffForCountry(storage::CountryId const & countryId);
|
||||
void AbortDiffScheme();
|
||||
|
||||
Status GetStatus() const;
|
||||
|
||||
private:
|
||||
template <typename Fn>
|
||||
bool WithNotAppliedDiff(storage::CountryId const & countryId, Fn && fn) const
|
||||
{
|
||||
if (m_status != Status::Available)
|
||||
return false;
|
||||
|
||||
auto const it = m_diffs.find(countryId);
|
||||
if (it == m_diffs.cend() || it->second.m_isApplied)
|
||||
return false;
|
||||
|
||||
fn(it->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadChecker m_threadChecker;
|
||||
|
||||
Status m_status = Status::NotAvailable;
|
||||
NameDiffInfoMap m_diffs;
|
||||
};
|
||||
} // namespace diffs
|
||||
} // namespace storage
|
||||
Loading…
Add table
Add a link
Reference in a new issue