summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2015-03-04 12:32:14 +0100
committerKonstantin Käfer <mail@kkaefer.com>2015-03-06 08:21:47 -0800
commit9781785ab73e8394e8b92625cc4741952f47955d (patch)
tree1b9e6b86c1c9ca19bb1bf1c52bcd0e41410ced66 /src
parent8c0acecbe362be4a40638491b67ee5fe3d23a65e (diff)
downloadqtlocation-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')
-rw-r--r--src/mbgl/map/environment.cpp39
-rw-r--r--src/mbgl/map/environment.hpp44
-rw-r--r--src/mbgl/map/map.cpp40
-rw-r--r--src/mbgl/map/raster_tile_data.cpp7
-rw-r--r--src/mbgl/map/raster_tile_data.hpp2
-rw-r--r--src/mbgl/map/source.cpp47
-rw-r--r--src/mbgl/map/source.hpp22
-rw-r--r--src/mbgl/map/sprite.cpp22
-rw-r--r--src/mbgl/map/sprite.hpp7
-rw-r--r--src/mbgl/map/tile_data.cpp15
-rw-r--r--src/mbgl/map/tile_data.hpp8
-rw-r--r--src/mbgl/map/vector_tile_data.cpp4
-rw-r--r--src/mbgl/map/vector_tile_data.hpp7
-rw-r--r--src/mbgl/storage/default_file_source.cpp62
-rw-r--r--src/mbgl/storage/request.cpp4
-rw-r--r--src/mbgl/text/glyph_store.cpp15
-rw-r--r--src/mbgl/text/glyph_store.hpp10
17 files changed, 235 insertions, 120 deletions
diff --git a/src/mbgl/map/environment.cpp b/src/mbgl/map/environment.cpp
new file mode 100644
index 0000000000..ee13d33ea7
--- /dev/null
+++ b/src/mbgl/map/environment.cpp
@@ -0,0 +1,39 @@
+#include <mbgl/map/environment.hpp>
+#include <mbgl/storage/file_source.hpp>
+
+#include <uv.h>
+
+#include <cassert>
+
+namespace mbgl {
+
+Environment::Environment(FileSource &fs) : fileSource(fs), loop(uv_loop_new()) {
+}
+
+void Environment::setup() {
+ mapThread = std::this_thread::get_id();
+}
+
+bool Environment::inMapThread() const {
+ return std::this_thread::get_id() == mapThread;
+}
+
+void Environment::requestAsync(const Resource &resource, std::function<void(const Response &)> callback) {
+ fileSource.request(resource, *this, std::move(callback));
+}
+
+Request *Environment::request(const Resource &resource, std::function<void(const Response &)> callback) {
+ assert(inMapThread());
+ return fileSource.request(resource, loop, *this, std::move(callback));
+}
+
+void Environment::cancelRequest(Request *req) {
+ assert(inMapThread());
+ fileSource.cancel(req);
+}
+
+void Environment::terminate() {
+ fileSource.abort(*this);
+}
+
+}
diff --git a/src/mbgl/map/environment.hpp b/src/mbgl/map/environment.hpp
new file mode 100644
index 0000000000..b68a7b9e2f
--- /dev/null
+++ b/src/mbgl/map/environment.hpp
@@ -0,0 +1,44 @@
+#ifndef MBGL_MAP_MAP_ENVIRONMENT
+#define MBGL_MAP_MAP_ENVIRONMENT
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/util.hpp>
+
+#include <thread>
+#include <functional>
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace mbgl {
+
+class FileSource;
+class Request;
+class Response;
+struct Resource;
+
+class Environment : private util::noncopyable {
+public:
+ Environment(FileSource &);
+
+ void setup();
+
+ bool inMapThread() const;
+
+ void requestAsync(const Resource &, std::function<void(const Response &)>);
+ Request *request(const Resource &, std::function<void(const Response &)>);
+ void cancelRequest(Request *);
+
+ // Request to terminate the environment.
+ void terminate();
+
+private:
+ FileSource &fileSource;
+ std::thread::id mapThread;
+
+public:
+ uv_loop_t *const loop;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 518bc5bb96..0cd7d3621e 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -1,4 +1,5 @@
#include <mbgl/map/map.hpp>
+#include <mbgl/map/environment.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/map/source.hpp>
@@ -25,6 +26,7 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/mapbox.hpp>
+#include <mbgl/util/exception.hpp>
#include <algorithm>
#include <iostream>
@@ -57,16 +59,14 @@ const static bool uvVersionCheck = []() {
using namespace mbgl;
Map::Map(View& view_, FileSource& fileSource_)
- : loop(util::make_unique<uv::loop>()),
+ : env(util::make_unique<Environment>(fileSource_)),
view(view_),
-#ifdef DEBUG
mainThread(std::this_thread::get_id()),
mapThread(mainThread),
-#endif
transform(view_),
fileSource(fileSource_),
glyphAtlas(util::make_unique<GlyphAtlas>(1024, 1024)),
- glyphStore(std::make_shared<GlyphStore>(fileSource)),
+ glyphStore(std::make_shared<GlyphStore>(*env)),
spriteAtlas(util::make_unique<SpriteAtlas>(512, 512)),
lineAtlas(util::make_unique<LineAtlas>(512, 512)),
texturePool(std::make_shared<TexturePool>()),
@@ -92,7 +92,7 @@ Map::~Map() {
texturePool.reset();
workers.reset();
- uv_run(**loop, UV_RUN_DEFAULT);
+ uv_run(env->loop, UV_RUN_DEFAULT);
}
uv::worker &Map::getWorker() {
@@ -112,7 +112,7 @@ void Map::start(bool startPaused) {
isStopped = false;
// Setup async notifications
- asyncTerminate = util::make_unique<uv::async>(**loop, [this]() {
+ asyncTerminate = util::make_unique<uv::async>(env->loop, [this]() {
assert(std::this_thread::get_id() == mapThread);
// Remove all of these to make sure they are destructed in the correct thread.
@@ -127,7 +127,7 @@ void Map::start(bool startPaused) {
asyncTerminate.reset();
});
- asyncRender = util::make_unique<uv::async>(**loop, [this]() {
+ asyncRender = util::make_unique<uv::async>(env->loop, [this]() {
assert(std::this_thread::get_id() == mapThread);
if (state.hasSize()) {
@@ -207,7 +207,7 @@ void Map::pause(bool waitForPause) {
pausing = true;
mutexRun.unlock();
- uv_stop(**loop);
+ uv_stop(env->loop);
rerender(); // Needed to ensure uv_stop is seen and uv_run exits, otherwise we deadlock on wait_for_pause
if (waitForPause) {
@@ -242,12 +242,14 @@ void Map::run() {
}
if (mode == Mode::Static && !style && styleURL.empty()) {
- throw exception("Style is not set");
+ throw util::Exception("Style is not set");
}
view.activate();
- workers = util::make_unique<uv::worker>(**loop, 4, "Tile Worker");
+ workers = util::make_unique<uv::worker>(env->loop, 4, "Tile Worker");
+
+ env->setup();
setup();
prepare();
@@ -255,15 +257,15 @@ void Map::run() {
if (mode == Mode::Continuous) {
terminating = false;
while(!terminating) {
- uv_run(**loop, UV_RUN_DEFAULT);
+ uv_run(env->loop, UV_RUN_DEFAULT);
checkForPause();
}
} else {
- uv_run(**loop, UV_RUN_DEFAULT);
+ uv_run(env->loop, UV_RUN_DEFAULT);
}
// Run the event loop once more to make sure our async delete handlers are called.
- uv_run(**loop, UV_RUN_ONCE);
+ uv_run(env->loop, UV_RUN_ONCE);
// If the map rendering wasn't started asynchronously, we perform one render
// *after* all events have been processed.
@@ -376,7 +378,7 @@ util::ptr<Sprite> Map::getSprite() {
const float pixelRatio = state.getPixelRatio();
const std::string &sprite_url = style->getSpriteURL();
if (!sprite || sprite->pixelRatio != pixelRatio) {
- sprite = Sprite::Create(sprite_url, pixelRatio, fileSource);
+ sprite = Sprite::Create(sprite_url, pixelRatio, *env);
}
return sprite;
@@ -621,7 +623,7 @@ void Map::updateSources() {
if (source->enabled) {
if (!source->source) {
source->source = std::make_shared<Source>(source->info);
- source->source->load(*this, fileSource);
+ source->source->load(*this, *env);
}
} else {
source->source.reset();
@@ -648,10 +650,8 @@ void Map::updateSources(const util::ptr<StyleLayerGroup> &group) {
void Map::updateTiles() {
for (const auto& source : activeSources) {
- source->source->update(*this, getWorker(),
- style, *glyphAtlas, *glyphStore,
- *spriteAtlas, getSprite(),
- *texturePool, fileSource, ***loop, [this](){ update(); });
+ source->source->update(*this, *env, getWorker(), style, *glyphAtlas, *glyphStore,
+ *spriteAtlas, getSprite(), *texturePool, [this]() { update(); });
}
}
@@ -659,7 +659,7 @@ void Map::prepare() {
if (!style) {
style = std::make_shared<Style>();
- fileSource.request({ Resource::Kind::JSON, styleURL}, **loop, [&](const Response &res) {
+ env->request({ Resource::Kind::JSON, styleURL}, [&](const Response &res) {
if (res.status == Response::Successful) {
// Calculate the base
const size_t pos = styleURL.rfind('/');
diff --git a/src/mbgl/map/raster_tile_data.cpp b/src/mbgl/map/raster_tile_data.cpp
index 1ca9ef8041..4cd7fc2b5e 100644
--- a/src/mbgl/map/raster_tile_data.cpp
+++ b/src/mbgl/map/raster_tile_data.cpp
@@ -4,10 +4,9 @@
using namespace mbgl;
-
-RasterTileData::RasterTileData(Tile::ID const& id_, TexturePool& texturePool, const SourceInfo& source_, FileSource& fileSource_)
- : TileData(id_, source_, fileSource_),
- bucket(texturePool, layout) {
+RasterTileData::RasterTileData(Tile::ID const &id_, TexturePool &texturePool,
+ const SourceInfo &source_, Environment &env_)
+ : TileData(id_, source_, env_), bucket(texturePool, layout) {
}
RasterTileData::~RasterTileData() {
diff --git a/src/mbgl/map/raster_tile_data.hpp b/src/mbgl/map/raster_tile_data.hpp
index 9a8578a61e..2413e13fb0 100644
--- a/src/mbgl/map/raster_tile_data.hpp
+++ b/src/mbgl/map/raster_tile_data.hpp
@@ -17,7 +17,7 @@ class RasterTileData : public TileData {
friend class TileParser;
public:
- RasterTileData(Tile::ID const& id, TexturePool&, const SourceInfo&, FileSource &);
+ RasterTileData(Tile::ID const &id, TexturePool &, const SourceInfo &, Environment &);
~RasterTileData();
void parse() override;
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp
index d9236b19b3..ec3a1b8e00 100644
--- a/src/mbgl/map/source.cpp
+++ b/src/mbgl/map/source.cpp
@@ -1,12 +1,14 @@
#include <mbgl/map/source.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/map/environment.hpp>
#include <mbgl/map/transform.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/raster.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/texture_pool.hpp>
-#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
#include <mbgl/util/vec.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/std.hpp>
@@ -32,7 +34,7 @@ Source::Source(SourceInfo& info_)
// Note: This is a separate function that must be called exactly once after creation
// The reason this isn't part of the constructor is that calling shared_from_this() in
// the constructor fails.
-void Source::load(Map& map, FileSource& fileSource) {
+void Source::load(Map &map, Environment &env) {
if (info.url.empty()) {
loaded = true;
return;
@@ -41,7 +43,7 @@ void Source::load(Map& map, FileSource& fileSource) {
util::ptr<Source> source = shared_from_this();
const std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken());
- fileSource.request({ Resource::Kind::JSON, url }, **map.loop, [source, &map](const Response &res) {
+ env.request({ Resource::Kind::JSON, url }, [source, &map](const Response &res) {
if (res.status != Response::Successful) {
Log::Warning(Event::General, "Failed to load source TileJSON: %s", res.message.c_str());
return;
@@ -153,13 +155,11 @@ TileData::State Source::hasTile(const Tile::ID& id) {
return TileData::State::invalid;
}
-TileData::State Source::addTile(Map& map, uv::worker& worker,
- util::ptr<Style> style,
- GlyphAtlas& glyphAtlas, GlyphStore& glyphStore,
- SpriteAtlas& spriteAtlas, util::ptr<Sprite> sprite,
- FileSource& fileSource, uv_loop_t &loop, TexturePool& texturePool,
- const Tile::ID& id,
- std::function<void ()> callback) {
+TileData::State Source::addTile(Map &map, Environment &env, uv::worker &worker,
+ util::ptr<Style> style, GlyphAtlas &glyphAtlas,
+ GlyphStore &glyphStore, SpriteAtlas &spriteAtlas,
+ util::ptr<Sprite> sprite, TexturePool &texturePool,
+ const Tile::ID &id, std::function<void()> callback) {
const TileData::State state = hasTile(id);
if (state != TileData::State::invalid) {
@@ -190,14 +190,14 @@ TileData::State Source::addTile(Map& map, uv::worker& worker,
new_tile.data = std::make_shared<VectorTileData>(normalized_id, map.getMaxZoom(), style,
glyphAtlas, glyphStore,
spriteAtlas, sprite,
- info, fileSource);
+ info, env);
} else if (info.type == SourceType::Raster) {
- new_tile.data = std::make_shared<RasterTileData>(normalized_id, texturePool, info, fileSource);
+ new_tile.data = std::make_shared<RasterTileData>(normalized_id, texturePool, info, env);
} else {
throw std::runtime_error("source type not implemented");
}
- new_tile.data->request(worker, loop, map.getState().getPixelRatio(), callback);
+ new_tile.data->request(worker, map.getState().getPixelRatio(), callback);
tile_data.emplace(new_tile.data->id, new_tile.data);
}
@@ -283,12 +283,16 @@ bool Source::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::
return false;
}
-void Source::update(Map& map, uv::worker& worker,
+void Source::update(Map &map,
+ Environment &env,
+ uv::worker &worker,
util::ptr<Style> style,
- GlyphAtlas& glyphAtlas, GlyphStore& glyphStore,
- SpriteAtlas& spriteAtlas, util::ptr<Sprite> sprite,
- TexturePool& texturePool, FileSource& fileSource, uv_loop_t& loop,
- std::function<void ()> callback) {
+ GlyphAtlas &glyphAtlas,
+ GlyphStore &glyphStore,
+ SpriteAtlas &spriteAtlas,
+ util::ptr<Sprite> sprite,
+ TexturePool &texturePool,
+ std::function<void()> callback) {
if (!loaded || map.getTime() <= updated)
return;
@@ -308,11 +312,8 @@ void Source::update(Map& map, uv::worker& worker,
// Add existing child/parent tiles if the actual tile is not yet loaded
for (const Tile::ID& id : required) {
- const TileData::State state = addTile(map, worker, style,
- glyphAtlas, glyphStore,
- spriteAtlas, sprite,
- fileSource, loop, texturePool,
- id, callback);
+ const TileData::State state = addTile(map, env, worker, style, glyphAtlas, glyphStore,
+ spriteAtlas, sprite, texturePool, id, callback);
if (state != TileData::State::parsed) {
// The tile we require is not yet loaded. Try to find a parent or
diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp
index 2c0e444225..061908b89d 100644
--- a/src/mbgl/map/source.hpp
+++ b/src/mbgl/map/source.hpp
@@ -18,11 +18,11 @@
namespace mbgl {
class Map;
+class Environment;
class GlyphAtlas;
class GlyphStore;
class SpriteAtlas;
class Sprite;
-class FileSource;
class TexturePool;
class Style;
class Painter;
@@ -34,13 +34,9 @@ class Source : public std::enable_shared_from_this<Source>, private util::noncop
public:
Source(SourceInfo&);
- void load(Map&, FileSource&);
- void update(Map&, uv::worker&,
- util::ptr<Style>,
- GlyphAtlas&, GlyphStore&,
- SpriteAtlas&, util::ptr<Sprite>,
- TexturePool&, FileSource&, uv_loop_t& loop,
- std::function<void ()> callback);
+ void load(Map &, Environment &);
+ void update(Map &, Environment &, uv::worker &, util::ptr<Style>, GlyphAtlas &, GlyphStore &,
+ SpriteAtlas &, util::ptr<Sprite>, TexturePool &, std::function<void()> callback);
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
void drawClippingMasks(Painter &painter);
@@ -59,13 +55,9 @@ private:
int32_t coveringZoomLevel(const TransformState&) const;
std::forward_list<Tile::ID> coveringTiles(const TransformState&) const;
- TileData::State addTile(Map&, uv::worker&,
- util::ptr<Style>,
- GlyphAtlas&, GlyphStore&,
- SpriteAtlas&, util::ptr<Sprite>,
- FileSource&, uv_loop_t &, TexturePool&,
- const Tile::ID&,
- std::function<void ()> callback);
+ TileData::State addTile(Map &, Environment &, uv::worker &, util::ptr<Style>, GlyphAtlas &,
+ GlyphStore &, SpriteAtlas &, util::ptr<Sprite>, TexturePool &,
+ const Tile::ID &, std::function<void()> callback);
TileData::State hasTile(const Tile::ID& id);
diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp
index 9543fe083a..4be92ff73f 100644
--- a/src/mbgl/map/sprite.cpp
+++ b/src/mbgl/map/sprite.cpp
@@ -5,7 +5,9 @@
#include <string>
#include <mbgl/platform/platform.hpp>
-#include <mbgl/storage/file_source.hpp>
+#include <mbgl/map/environment.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/std.hpp>
@@ -22,9 +24,9 @@ SpritePosition::SpritePosition(uint16_t x_, uint16_t y_, uint16_t width_, uint16
sdf(sdf_) {
}
-util::ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio, FileSource& fileSource) {
+util::ptr<Sprite> Sprite::Create(const std::string &base_url, float pixelRatio, Environment &env) {
util::ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio));
- sprite->load(fileSource);
+ sprite->load(env);
return sprite;
}
@@ -51,7 +53,7 @@ Sprite::operator bool() const {
// Note: This is a separate function that must be called exactly once after creation
// The reason this isn't part of the constructor is that calling shared_from_this() in
// the constructor fails.
-void Sprite::load(FileSource& fileSource) {
+void Sprite::load(Environment &env) {
if (!valid) {
// Treat a non-existent sprite as a successfully loaded empty sprite.
@@ -63,29 +65,25 @@ void Sprite::load(FileSource& fileSource) {
util::ptr<Sprite> sprite = shared_from_this();
- fileSource.request({ Resource::Kind::JSON, jsonURL }, [sprite](const Response &res) {
+ env.request({ Resource::Kind::JSON, jsonURL }, [sprite](const Response &res) {
if (res.status == Response::Successful) {
sprite->body = res.data;
sprite->parseJSON();
sprite->complete();
} else {
Log::Warning(Event::Sprite, "Failed to load sprite info: %s", res.message.c_str());
- if (!sprite->future.valid()) {
- sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
- }
+ sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
}
});
- fileSource.request({ Resource::Kind::Image, spriteURL }, [sprite](const Response &res) {
+ env.request({ Resource::Kind::Image, spriteURL }, [sprite](const Response &res) {
if (res.status == Response::Successful) {
sprite->image = res.data;
sprite->parseImage();
sprite->complete();
} else {
Log::Warning(Event::Sprite, "Failed to load sprite image: %s", res.message.c_str());
- if (!sprite->future.valid()) {
- sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
- }
+ sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
}
});
}
diff --git a/src/mbgl/map/sprite.hpp b/src/mbgl/map/sprite.hpp
index d4b54ba1b5..cb0c274dee 100644
--- a/src/mbgl/map/sprite.hpp
+++ b/src/mbgl/map/sprite.hpp
@@ -14,7 +14,7 @@
namespace mbgl {
-class FileSource;
+class Environment;
class SpritePosition {
public:
@@ -34,11 +34,12 @@ public:
class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable {
private:
struct Key {};
- void load(FileSource& fileSource);
+ void load(Environment &env);
public:
Sprite(const Key &, const std::string& base_url, float pixelRatio);
- static util::ptr<Sprite> Create(const std::string& base_url, float pixelRatio, FileSource& fileSource);
+ static util::ptr<Sprite>
+ Create(const std::string &base_url, float pixelRatio, Environment &env);
const SpritePosition &getSpritePosition(const std::string& name) const;
diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp
index 9d48041239..53d36dfe8b 100644
--- a/src/mbgl/map/tile_data.cpp
+++ b/src/mbgl/map/tile_data.cpp
@@ -1,5 +1,6 @@
#include <mbgl/map/tile_data.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/map/environment.hpp>
#include <mbgl/style/style_source.hpp>
#include <mbgl/util/token.hpp>
@@ -10,12 +11,12 @@
using namespace mbgl;
-TileData::TileData(Tile::ID const& id_, const SourceInfo& source_, FileSource& fileSource_)
+TileData::TileData(Tile::ID const& id_, const SourceInfo& source_, Environment& env_)
: id(id_),
name(id),
state(State::initial),
source(source_),
- fileSource(fileSource_),
+ env(env_),
debugBucket(debugFontBuffer) {
// Initialize tile debug coordinates
debugFontBuffer.addText(name.c_str(), 50, 200, 5);
@@ -23,7 +24,7 @@ TileData::TileData(Tile::ID const& id_, const SourceInfo& source_, FileSource& f
TileData::~TileData() {
if (req) {
- fileSource.cancel(req);
+ env.cancelRequest(req);
}
}
@@ -31,8 +32,7 @@ const std::string TileData::toString() const {
return std::string { "[tile " } + name + "]";
}
-void TileData::request(uv::worker &worker, uv_loop_t &loop,
- float pixelRatio, std::function<void()> callback) {
+void TileData::request(uv::worker &worker, float pixelRatio, std::function<void()> callback) {
if (source.tiles.empty())
return;
@@ -53,9 +53,8 @@ void TileData::request(uv::worker &worker, uv_loop_t &loop,
state = State::loading;
- // Note: Somehow this feels slower than the change to request_http()
std::weak_ptr<TileData> weak_tile = shared_from_this();
- req = fileSource.request({ Resource::Kind::Tile, url }, &loop, [weak_tile, url, callback, &worker](const Response &res) {
+ req = env.request({ Resource::Kind::Tile, url }, [weak_tile, url, callback, &worker](const Response &res) {
util::ptr<TileData> tile = weak_tile.lock();
if (!tile || tile->state == State::obsolete) {
// noop. Tile is obsolete and we're now just waiting for the refcount
@@ -84,7 +83,7 @@ void TileData::cancel() {
state = State::obsolete;
}
if (req) {
- fileSource.cancel(req);
+ env.cancelRequest(req);
req = nullptr;
}
}
diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp
index fcd741a1f8..66c0fbba2e 100644
--- a/src/mbgl/map/tile_data.hpp
+++ b/src/mbgl/map/tile_data.hpp
@@ -23,7 +23,7 @@ typedef struct uv_loop_s uv_loop_t;
namespace mbgl {
class Map;
-class FileSource;
+class Environment;
class Painter;
class SourceInfo;
class StyleLayer;
@@ -48,10 +48,10 @@ public:
};
public:
- TileData(Tile::ID const& id, const SourceInfo&, FileSource&);
+ TileData(Tile::ID const &id, const SourceInfo &, Environment &);
~TileData();
- void request(uv::worker&, uv_loop_t&, float pixelRatio, std::function<void ()> callback);
+ void request(uv::worker&, float pixelRatio, std::function<void ()> callback);
void reparse(uv::worker&, std::function<void ()> callback);
void cancel();
const std::string toString() const;
@@ -72,7 +72,7 @@ public:
public:
const SourceInfo& source;
- FileSource& fileSource;
+ Environment &env;
protected:
Request *req = nullptr;
diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp
index 68974aadf4..66fed0706b 100644
--- a/src/mbgl/map/vector_tile_data.cpp
+++ b/src/mbgl/map/vector_tile_data.cpp
@@ -14,8 +14,8 @@ VectorTileData::VectorTileData(Tile::ID const& id_,
float mapMaxZoom, util::ptr<Style> style_,
GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_,
SpriteAtlas& spriteAtlas_, util::ptr<Sprite> sprite_,
- const SourceInfo& source_, FileSource &fileSource_)
- : TileData(id_, source_, fileSource_),
+ const SourceInfo& source_, Environment &env_)
+ : TileData(id_, source_, env_),
glyphAtlas(glyphAtlas_),
glyphStore(glyphStore_),
spriteAtlas(spriteAtlas_),
diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp
index feb3c6238b..1c48fc5f23 100644
--- a/src/mbgl/map/vector_tile_data.hpp
+++ b/src/mbgl/map/vector_tile_data.hpp
@@ -30,11 +30,8 @@ class VectorTileData : public TileData {
friend class TileParser;
public:
- VectorTileData(Tile::ID const&,
- float mapMaxZoom, util::ptr<Style>,
- GlyphAtlas&, GlyphStore&,
- SpriteAtlas&, util::ptr<Sprite>,
- const SourceInfo&, FileSource &);
+ VectorTileData(Tile::ID const &, float mapMaxZoom, util::ptr<Style>, GlyphAtlas &, GlyphStore &,
+ SpriteAtlas &, util::ptr<Sprite>, const SourceInfo &, Environment &);
~VectorTileData();
void parse() override;
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) {
diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp
index f89f42e909..ab1776c04b 100644
--- a/src/mbgl/text/glyph_store.cpp
+++ b/src/mbgl/text/glyph_store.cpp
@@ -1,5 +1,6 @@
#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/map/environment.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/utf.hpp>
@@ -137,9 +138,11 @@ void FontStack::lineWrap(Shaping &shaping, const float lineHeight, const float m
align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line);
}
-GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, FileSource& fileSource)
- : future(promise.get_future().share())
-{
+GlyphPBF::GlyphPBF(const std::string &glyphURL,
+ const std::string &fontStack,
+ GlyphRange glyphRange,
+ Environment &env)
+ : future(promise.get_future().share()) {
// Load the glyph set URL
std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
if (name == "fontstack") return util::percentEncode(fontStack);
@@ -148,7 +151,7 @@ GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, Gl
});
// The prepare call jumps back to the main thread.
- fileSource.request({ Resource::Kind::Glyphs, url }, [&, url](const Response &res) {
+ env.requestAsync({ Resource::Kind::Glyphs, url }, [&, url](const Response &res) {
if (res.status != Response::Successful) {
// Something went wrong with loading the glyph pbf. Pass on the error to the future listeners.
const std::string msg = std::string { "[ERROR] failed to load glyphs: " } + res.message;
@@ -223,7 +226,7 @@ void GlyphPBF::parse(FontStack &stack) {
data.clear();
}
-GlyphStore::GlyphStore(FileSource& fileSource_) : fileSource(fileSource_), mtx(util::make_unique<uv::mutex>()) {}
+GlyphStore::GlyphStore(Environment& env_) : env(env_), mtx(util::make_unique<uv::mutex>()) {}
void GlyphStore::setURL(const std::string &url) {
glyphURL = url;
@@ -265,7 +268,7 @@ std::shared_future<GlyphPBF &> GlyphStore::loadGlyphRange(const std::string &fon
auto range_it = rangeSets.find(range);
if (range_it == rangeSets.end()) {
// We don't have this glyph set yet for this font stack.
- range_it = rangeSets.emplace(range, util::make_unique<GlyphPBF>(glyphURL, fontStack, range, fileSource)).first;
+ range_it = rangeSets.emplace(range, util::make_unique<GlyphPBF>(glyphURL, fontStack, range, env)).first;
}
return range_it->second->getFuture();
diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp
index 6839045d61..406234241d 100644
--- a/src/mbgl/text/glyph_store.hpp
+++ b/src/mbgl/text/glyph_store.hpp
@@ -17,6 +17,7 @@
namespace mbgl {
class FileSource;
+class Environment;
class SDFGlyph {
public:
@@ -49,7 +50,10 @@ private:
class GlyphPBF {
public:
- GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, FileSource& fileSource);
+ GlyphPBF(const std::string &glyphURL,
+ const std::string &fontStack,
+ GlyphRange glyphRange,
+ Environment &env);
private:
GlyphPBF(const GlyphPBF &) = delete;
@@ -72,7 +76,7 @@ private:
// Manages Glyphrange PBF loading.
class GlyphStore {
public:
- GlyphStore(FileSource& fileSource);
+ GlyphStore(Environment &);
// Block until all specified GlyphRanges of the specified font stack are loaded.
void waitForGlyphRanges(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges);
@@ -88,7 +92,7 @@ private:
FontStack &createFontStack(const std::string &fontStack);
std::string glyphURL;
- FileSource& fileSource;
+ Environment &env;
std::unordered_map<std::string, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>> ranges;
std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks;
std::unique_ptr<uv::mutex> mtx;