diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2015-03-04 12:32:14 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2015-03-06 08:21:47 -0800 |
commit | 9781785ab73e8394e8b92625cc4741952f47955d (patch) | |
tree | 1b9e6b86c1c9ca19bb1bf1c52bcd0e41410ced66 /src/mbgl/storage | |
parent | 8c0acecbe362be4a40638491b67ee5fe3d23a65e (diff) | |
download | qtlocation-mapboxgl-9781785ab73e8394e8b92625cc4741952f47955d.tar.gz |
scope Requests to an Environment object for easier cancelation
we are now scoping all file requests to an environment object. The FileSource implementation treats
this as an opaque pointer, but allows canceling all Requests that are associated with that pointer.
This is necessary to abort all file requests that originated from a particular Map object. Aborting
a file request is different from canceling a file request: A canceled request doesn't have its
callback called, while an aborted request will have its callback called with an error, indicating
that the environment is going to be shut down.
Diffstat (limited to 'src/mbgl/storage')
-rw-r--r-- | src/mbgl/storage/default_file_source.cpp | 62 | ||||
-rw-r--r-- | src/mbgl/storage/request.cpp | 4 |
2 files changed, 52 insertions, 14 deletions
diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index c6b201b559..9f70ac9943 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -50,6 +50,10 @@ struct DefaultFileSource::ResultAction { struct DefaultFileSource::StopAction { }; +struct DefaultFileSource::AbortAction { + const Environment &env; +}; + DefaultFileSource::DefaultFileSource(FileCache *cache_, const std::string &root) : assetRoot(root.empty() ? platform::assetRoot() : root), @@ -105,8 +109,9 @@ SharedRequestBase *DefaultFileSource::find(const Resource &resource) { return nullptr; } -Request *DefaultFileSource::request(const Resource &resource, uv_loop_t *l, Callback callback) { - auto req = new Request(resource, l, std::move(callback)); +Request *DefaultFileSource::request(const Resource &resource, uv_loop_t *l, const Environment &env, + Callback callback) { + auto req = new Request(resource, l, env, std::move(callback)); // This function can be called from any thread. Make sure we're executing the actual call in the // file source loop by sending it over the queue. It will be processed in processAction(). @@ -114,8 +119,9 @@ Request *DefaultFileSource::request(const Resource &resource, uv_loop_t *l, Call return req; } -void DefaultFileSource::request(const Resource &resource, Callback callback) { - auto req = new Request(resource, nullptr, std::move(callback)); +void DefaultFileSource::request(const Resource &resource, const Environment &env, + Callback callback) { + auto req = new Request(resource, nullptr, env, std::move(callback)); // This function can be called from any thread. Make sure we're executing the actual call in the // file source loop by sending it over the queue. It will be processed in processAction(). @@ -130,6 +136,11 @@ void DefaultFileSource::cancel(Request *req) { queue->send(RemoveRequestAction{ req }); } +void DefaultFileSource::abort(const Environment &env) { + queue->send(AbortAction{ env }); +} + + void DefaultFileSource::process(AddRequestAction &action) { const Resource &resource = action.request->resource; @@ -209,18 +220,45 @@ void DefaultFileSource::process(ResultAction &action) { } } +// A stop action means the file source is about to be destructed. We need to cancel all requests +// for all environments. void DefaultFileSource::process(StopAction &) { - // Cancel all remaining requests. - for (auto it : pending) { - it.second->unsubscribeAll(); - } - pending.clear(); - + // There may not be any pending requests in this file source anymore. You must terminate all + // Map objects before deleting the FileSource. + assert(pending.empty()); assert(queue); queue->stop(); queue = nullptr; } +// Aborts all requests that are part of the current environment. +void DefaultFileSource::process(AbortAction &action) { + // Construct a cancellation response. + auto res = util::make_unique<Response>(); + res->status = Response::Error; + res->message = "Environment is terminating"; + std::shared_ptr<const Response> response = std::move(res); + + // Iterate through all pending requests and remove them in case they're abandoned. + util::erase_if(pending, [&](const std::pair<Resource, SharedRequestBase *> &it) -> bool { + // Obtain all pending requests that are in the current environment. + const auto aborted = it.second->removeAllInEnvironment(action.env); + + // Notify all observers. + for (auto req : aborted) { + req->notify(response); + } + + // Finally, remove all requests that are now abandoned. + if (it.second->abandoned()) { + it.second->cancel(); + return true; + } else { + return false; + } + }); +} + void DefaultFileSource::notify(SharedRequestBase *sharedRequest, const std::set<Request *> &observers, std::shared_ptr<const Response> response, FileCache::Hint hint) { @@ -235,8 +273,8 @@ void DefaultFileSource::notify(SharedRequestBase *sharedRequest, } // Notify all observers. - for (auto it : observers) { - it->notify(response); + for (auto req : observers) { + req->notify(response); } } diff --git a/src/mbgl/storage/request.cpp b/src/mbgl/storage/request.cpp index de18138ec2..48b5b774d2 100644 --- a/src/mbgl/storage/request.cpp +++ b/src/mbgl/storage/request.cpp @@ -13,8 +13,8 @@ namespace mbgl { // Note: This requires that loop is running in the current thread (or not yet running). -Request::Request(const Resource &resource_, uv_loop_t *loop, Callback callback_) - : callback(callback_), resource(resource_) { +Request::Request(const Resource &resource_, uv_loop_t *loop, const Environment &env_, Callback callback_) + : callback(callback_), resource(resource_), env(env_) { // When there is no loop supplied (== nullptr), the callback will be fired in an arbitrary // thread (the thread notify() is called from) rather than kicking back to the calling thread. if (loop) { |