diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/map/map_context.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/raster_tile_data.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/source.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/sprite.cpp | 8 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile_data.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/storage/default_file_source.cpp | 78 | ||||
-rw-r--r-- | src/mbgl/storage/default_file_source_impl.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/storage/request.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/storage/response.cpp | 12 | ||||
-rw-r--r-- | src/mbgl/text/glyph_pbf.cpp | 4 |
10 files changed, 98 insertions, 23 deletions
diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 0888ef2846..b197ea12f3 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -106,6 +106,10 @@ void MapContext::setStyleURL(const std::string& url) { FileSource* fs = util::ThreadContext::getFileSource(); styleRequest = fs->request({ Resource::Kind::Style, styleURL }, util::RunLoop::getLoop(), [this, base](const Response &res) { + if (res.stale) { + // Only handle fresh responses. + return; + } styleRequest = nullptr; if (res.status == Response::Successful) { diff --git a/src/mbgl/map/raster_tile_data.cpp b/src/mbgl/map/raster_tile_data.cpp index 4ae9189a0b..cc7b6b548f 100644 --- a/src/mbgl/map/raster_tile_data.cpp +++ b/src/mbgl/map/raster_tile_data.cpp @@ -31,6 +31,10 @@ void RasterTileData::request(float pixelRatio, FileSource* fs = util::ThreadContext::getFileSource(); req = fs->request({ Resource::Kind::Tile, url }, util::RunLoop::getLoop(), [url, callback, this](const Response &res) { + if (res.stale) { + // Only handle fresh responses. + return; + } req = nullptr; if (res.status == Response::NotFound) { diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index d723e308b1..7e30682895 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -149,6 +149,10 @@ void Source::load() { FileSource* fs = util::ThreadContext::getFileSource(); req = fs->request({ Resource::Kind::Source, info.url }, util::RunLoop::getLoop(), [this](const Response &res) { + if (res.stale) { + // Only handle fresh responses. + return; + } req = nullptr; if (res.status != Response::Successful) { diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp index 9c099b4aa2..a54d96f005 100644 --- a/src/mbgl/map/sprite.cpp +++ b/src/mbgl/map/sprite.cpp @@ -44,6 +44,10 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) FileSource* fs = util::ThreadContext::getFileSource(); loader->jsonRequest = fs->request({ Resource::Kind::SpriteJSON, jsonURL }, util::RunLoop::getLoop(), [this, jsonURL](const Response& res) { + if (res.stale) { + // Only handle fresh responses. + return; + } loader->jsonRequest = nullptr; if (res.status == Response::Successful) { loader->data->json = res.data; @@ -60,6 +64,10 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) loader->spriteRequest = fs->request({ Resource::Kind::SpriteImage, spriteURL }, util::RunLoop::getLoop(), [this, spriteURL](const Response& res) { + if (res.stale) { + // Only handle fresh responses. + return; + } loader->spriteRequest = nullptr; if (res.status == Response::Successful) { loader->data->image = res.data; diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 6aa643b16f..2e683daaff 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -43,6 +43,10 @@ void VectorTileData::request(float pixelRatio, const std::function<void()>& call FileSource* fs = util::ThreadContext::getFileSource(); req = fs->request({ Resource::Kind::Tile, url }, util::RunLoop::getLoop(), [url, callback, this](const Response &res) { + if (res.stale) { + // Only handle fresh responses. + return; + } req = nullptr; if (res.status == Response::NotFound) { diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index 7b3cff8253..71c42f6220 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -8,7 +8,6 @@ #include <mbgl/platform/log.hpp> #include <mbgl/util/uv_detail.hpp> -#include <mbgl/util/chrono.hpp> #include <mbgl/util/thread.hpp> #include <mbgl/util/mapbox.hpp> #include <mbgl/util/exception.hpp> @@ -102,43 +101,79 @@ void DefaultFileSource::Impl::add(Request* req) { const Resource& resource = req->resource; DefaultFileRequest* request = find(resource); - if (request) { - request->observers.insert(req); - return; + if (!request) { + request = &pending.emplace(resource, resource).first->second; } - request = &pending.emplace(resource, resource).first->second; + // Add this request as an observer so that it'll get notified when something about this + // request changes. request->observers.insert(req); - if (cache) { - startCacheRequest(request); + update(request); + + if (request->response) { + // We've got a response, so send the (potentially stale) response to the requester. + req->notify(request->response); + } +} + +void DefaultFileSource::Impl::update(DefaultFileRequest* request) { + if (request->response) { + // We've at least obtained a cache value, potentially we also got a final response. + // The observers have been notified already; send what we have to the new one as well. + + // Before returning the existing response, make sure that it is still fresh. + if (!request->response->stale && request->response->isExpired()) { + // Create a new Response object with `stale = true`, but the same data, and + // replace the current request object we have. + // TODO: Make content shared_ptrs so we won't make copies of the content. + auto response = std::make_shared<Response>(*request->response); + response->stale = true; + request->response = response; + } + + if (request->response->stale && !request->realRequest) { + // We've returned a stale response; now make sure the requester also gets a fresh + // response eventually. It's possible that there's already a request in progress. + // Note that this will also trigger updates to all other existing listeners. + // Since we already have data, we're going to verify + startRealRequest(request, request->response); + } + } else if (!request->cacheRequest && !request->realRequest) { + // There is no request in progress, and we don't have a response yet. This means we'll have + // to start the request ourselves. + if (cache) { + startCacheRequest(request); + } else { + startRealRequest(request); + } } else { - startRealRequest(request); + // There is a request in progress. We just have to wait. } } void DefaultFileSource::Impl::startCacheRequest(DefaultFileRequest* request) { // Check the cache for existing data so that we can potentially // revalidate the information without having to redownload everything. - request->cacheRequest = cache->get(request->resource, [this, request](std::unique_ptr<Response> response) { - auto expired = [&response] { - const int64_t now = std::chrono::duration_cast<std::chrono::seconds>( - SystemClock::now().time_since_epoch()).count(); - return response->expires <= now; - }; - - if (!response || expired()) { + request->cacheRequest = cache->get(request->resource, [this, request](std::shared_ptr<Response> response) { + request->cacheRequest = nullptr; + if (response) { + response->stale = response->isExpired(); + + // Notify in all cases; requestors can decide whether they want to use stale responses. + notify(request, response, FileCache::Hint::No); + } + + if (!response || response->stale) { // No response or stale cache. Run the real request. - startRealRequest(request, std::move(response)); - } else { - // The response is fresh. We're good to notify the caller. - notify(request, std::move(response), FileCache::Hint::No); + startRealRequest(request, response); } }); } void DefaultFileSource::Impl::startRealRequest(DefaultFileRequest* request, std::shared_ptr<const Response> response) { auto callback = [request, this] (std::shared_ptr<const Response> res, FileCache::Hint hint) { + request->realRequest = nullptr; notify(request, res, hint); }; @@ -181,6 +216,7 @@ void DefaultFileSource::Impl::notify(DefaultFileRequest* request, std::shared_pt assert(response); // Notify all observers. + request->response = response; for (auto req : request->observers) { req->notify(response); } @@ -189,8 +225,6 @@ void DefaultFileSource::Impl::notify(DefaultFileRequest* request, std::shared_pt // Store response in database cache->put(request->resource, response, hint); } - - pending.erase(request->resource); } } diff --git a/src/mbgl/storage/default_file_source_impl.hpp b/src/mbgl/storage/default_file_source_impl.hpp index bb28933798..980eedc118 100644 --- a/src/mbgl/storage/default_file_source_impl.hpp +++ b/src/mbgl/storage/default_file_source_impl.hpp @@ -15,6 +15,7 @@ class RequestBase; struct DefaultFileRequest { const Resource resource; std::set<Request*> observers; + std::shared_ptr<const Response> response; std::unique_ptr<WorkRequest> cacheRequest; RequestBase* realRequest = nullptr; @@ -39,6 +40,7 @@ public: private: DefaultFileRequest* find(const Resource&); + void update(DefaultFileRequest*); void startCacheRequest(DefaultFileRequest*); void startRealRequest(DefaultFileRequest*, std::shared_ptr<const Response> = nullptr); void notify(DefaultFileRequest*, std::shared_ptr<const Response>, FileCache::Hint); diff --git a/src/mbgl/storage/request.cpp b/src/mbgl/storage/request.cpp index f8ad555379..55913846cf 100644 --- a/src/mbgl/storage/request.cpp +++ b/src/mbgl/storage/request.cpp @@ -49,7 +49,6 @@ Request::~Request() = default; // Called in the FileSource thread. void Request::notify(const std::shared_ptr<const Response> &response_) { - assert(!std::atomic_load(&response)); assert(response_); std::atomic_store(&response, response_); async->send(); diff --git a/src/mbgl/storage/response.cpp b/src/mbgl/storage/response.cpp new file mode 100644 index 0000000000..628a2a3b99 --- /dev/null +++ b/src/mbgl/storage/response.cpp @@ -0,0 +1,12 @@ +#include <mbgl/storage/response.hpp> +#include <mbgl/util/chrono.hpp> + +namespace mbgl { + +bool Response::isExpired() const { + const int64_t now = std::chrono::duration_cast<std::chrono::seconds>( + SystemClock::now().time_since_epoch()).count(); + return expires <= now; +} + +} // namespace mbgl diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp index e37e656d91..f351e66c2a 100644 --- a/src/mbgl/text/glyph_pbf.cpp +++ b/src/mbgl/text/glyph_pbf.cpp @@ -75,6 +75,10 @@ GlyphPBF::GlyphPBF(GlyphStore* store, }); auto requestCallback = [this, store, fontStack, url](const Response &res) { + if (res.stale) { + // Only handle fresh responses. + return; + } req = nullptr; if (res.status != Response::Successful) { |