[core] default file source - ensure thread safety for local file and asset requests

This commit is contained in:
Ivo van Dongen
2017-05-26 17:49:33 +03:00
committed by Ivo van Dongen
parent b353f45fed
commit 89129379f1
2 changed files with 46 additions and 38 deletions

View File

@@ -140,9 +140,9 @@ public:
class Impl;
private:
// Shared so destruction is done on this thread
const std::shared_ptr<FileSource> assetFileSource;
const std::unique_ptr<util::Thread<Impl>> thread;
const std::unique_ptr<FileSource> assetFileSource;
const std::unique_ptr<FileSource> localFileSource;
std::string cachedBaseURL = mbgl::util::API_BASE_URL;
std::string cachedAccessToken;
};

View File

@@ -26,8 +26,10 @@ namespace mbgl {
class DefaultFileSource::Impl {
public:
Impl(const std::string& cachePath, uint64_t maximumCacheSize)
: offlineDatabase(cachePath, maximumCacheSize) {
Impl(std::shared_ptr<FileSource> assetFileSource_, const std::string& cachePath, uint64_t maximumCacheSize)
: assetFileSource(assetFileSource_)
, localFileSource(std::make_unique<LocalFileSource>())
, offlineDatabase(cachePath, maximumCacheSize) {
}
void setAPIBaseURL(const std::string& url) {
@@ -105,35 +107,45 @@ public:
}
void request(AsyncRequest* req, Resource resource, Callback callback) {
Resource revalidation = resource;
if (isAssetURL(resource.url)) {
//Asset request
tasks[req] = assetFileSource->request(resource, callback);
} else if (LocalFileSource::acceptsURL(resource.url)) {
//Local file request
tasks[req] = localFileSource->request(resource, callback);
} else {
// Try the offline database
Resource revalidation = resource;
const bool hasPrior = resource.priorEtag || resource.priorModified || resource.priorExpires;
if (!hasPrior || resource.necessity == Resource::Optional) {
auto offlineResponse = offlineDatabase.get(resource);
const bool hasPrior = resource.priorEtag || resource.priorModified || resource.priorExpires;
if (!hasPrior || resource.necessity == Resource::Optional) {
auto offlineResponse = offlineDatabase.get(resource);
if (resource.necessity == Resource::Optional && !offlineResponse) {
// Ensure there's always a response that we can send, so the caller knows that
// there's no optional data available in the cache.
offlineResponse.emplace();
offlineResponse->noContent = true;
offlineResponse->error = std::make_unique<Response::Error>(
Response::Error::Reason::NotFound, "Not found in offline database");
if (resource.necessity == Resource::Optional && !offlineResponse) {
// Ensure there's always a response that we can send, so the caller knows that
// there's no optional data available in the cache.
offlineResponse.emplace();
offlineResponse->noContent = true;
offlineResponse->error = std::make_unique<Response::Error>(
Response::Error::Reason::NotFound, "Not found in offline database");
}
if (offlineResponse) {
revalidation.priorModified = offlineResponse->modified;
revalidation.priorExpires = offlineResponse->expires;
revalidation.priorEtag = offlineResponse->etag;
callback(*offlineResponse);
}
}
if (offlineResponse) {
revalidation.priorModified = offlineResponse->modified;
revalidation.priorExpires = offlineResponse->expires;
revalidation.priorEtag = offlineResponse->etag;
callback(*offlineResponse);
// Get from the online file source
if (resource.necessity == Resource::Required) {
tasks[req] = onlineFileSource.request(revalidation, [=] (Response onlineResponse) {
this->offlineDatabase.put(revalidation, onlineResponse);
callback(onlineResponse);
});
}
}
if (resource.necessity == Resource::Required) {
tasks[req] = onlineFileSource.request(revalidation, [=] (Response onlineResponse) {
this->offlineDatabase.put(revalidation, onlineResponse);
callback(onlineResponse);
});
}
}
void cancel(AsyncRequest* req) {
@@ -158,6 +170,9 @@ private:
std::make_unique<OfflineDownload>(regionID, offlineDatabase.getRegionDefinition(regionID), offlineDatabase, onlineFileSource)).first->second;
}
// shared so that destruction is done on the creating thread
const std::shared_ptr<FileSource> assetFileSource;
const std::unique_ptr<FileSource> localFileSource;
OfflineDatabase offlineDatabase;
OnlineFileSource onlineFileSource;
std::unordered_map<AsyncRequest*, std::unique_ptr<AsyncRequest>> tasks;
@@ -173,10 +188,9 @@ DefaultFileSource::DefaultFileSource(const std::string& cachePath,
DefaultFileSource::DefaultFileSource(const std::string& cachePath,
std::unique_ptr<FileSource>&& assetFileSource_,
uint64_t maximumCacheSize)
: thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"DefaultFileSource", util::ThreadPriority::Low},
cachePath, maximumCacheSize)),
assetFileSource(std::move(assetFileSource_)),
localFileSource(std::make_unique<LocalFileSource>()) {
: assetFileSource(std::move(assetFileSource_))
, thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"DefaultFileSource", util::ThreadPriority::Low},
assetFileSource, cachePath, maximumCacheSize)) {
}
DefaultFileSource::~DefaultFileSource() = default;
@@ -228,13 +242,7 @@ std::unique_ptr<AsyncRequest> DefaultFileSource::request(const Resource& resourc
std::unique_ptr<AsyncRequest> workRequest;
};
if (isAssetURL(resource.url)) {
return assetFileSource->request(resource, callback);
} else if (LocalFileSource::acceptsURL(resource.url)) {
return localFileSource->request(resource, callback);
} else {
return std::make_unique<DefaultFileRequest>(resource, callback, *thread);
}
return std::make_unique<DefaultFileRequest>(resource, callback, *thread);
}
void DefaultFileSource::listOfflineRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) {