diff options
-rw-r--r-- | common/headless_view.cpp | 4 | ||||
-rw-r--r-- | common/headless_view.hpp | 1 | ||||
-rw-r--r-- | include/mbgl/map/tile_data.hpp | 2 | ||||
-rw-r--r-- | include/mbgl/util/uv-worker.h | 2 | ||||
-rw-r--r-- | src/map/map.cpp | 17 | ||||
-rw-r--r-- | src/map/vector_tile_data.cpp | 16 | ||||
-rw-r--r-- | src/storage/file_source.cpp | 3 | ||||
-rw-r--r-- | src/storage/http_request.cpp | 14 | ||||
-rw-r--r-- | src/storage/sqlite_store.cpp | 2 | ||||
-rw-r--r-- | src/util/uv-worker.c | 28 | ||||
-rw-r--r-- | test/fixtures/fixture_request.cpp | 115 |
11 files changed, 102 insertions, 102 deletions
diff --git a/common/headless_view.cpp b/common/headless_view.cpp index ed00f48e82..ace41d38c0 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -163,6 +163,10 @@ HeadlessView::~HeadlessView() { #endif } +void HeadlessView::notify() { + // no-op +} + void HeadlessView::notify_map_change(mbgl::MapChange /*change*/, mbgl::timestamp /*delay*/) { // no-op } diff --git a/common/headless_view.hpp b/common/headless_view.hpp index a8ce4aa325..42f9c46da2 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -21,6 +21,7 @@ public: void resize(uint16_t width, uint16_t height, float pixelRatio); + void notify(); void notify_map_change(MapChange change, timestamp delay = 0); void make_active(); void swap(); diff --git a/include/mbgl/map/tile_data.hpp b/include/mbgl/map/tile_data.hpp index 07cf19c5c8..823523679a 100644 --- a/include/mbgl/map/tile_data.hpp +++ b/include/mbgl/map/tile_data.hpp @@ -41,7 +41,7 @@ public: public: TileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source); - ~TileData(); + virtual ~TileData(); void request(); void cancel(); diff --git a/include/mbgl/util/uv-worker.h b/include/mbgl/util/uv-worker.h index a9c9aff500..eff1169a2b 100644 --- a/include/mbgl/util/uv-worker.h +++ b/include/mbgl/util/uv-worker.h @@ -21,11 +21,13 @@ struct uv_worker_s { #ifndef NDEBUG unsigned long thread_id; #endif + uv_loop_t *loop; uv_messenger_t *msgr; uv_chan_t chan; const char *name; int count; uv_worker_close_cb close_cb; + int active; }; int uv_worker_init(uv_worker_t *worker, uv_loop_t *loop, int count, const char *name); diff --git a/src/map/map.cpp b/src/map/map.cpp index f71ecdb270..4b797ceae3 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -58,6 +58,15 @@ Map::~Map() { if (async) { stop(); } + + // Explicitly reset all pointers. + texturepool.reset(); + sprite.reset(); + spriteAtlas.reset(); + glyphStore.reset(); + glyphAtlas.reset(); + style.reset(); + fileSource.reset(); } uv::worker &Map::getWorker() { @@ -265,8 +274,14 @@ void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) { // TODO: Make threadsafe. styleJSON.swap(newStyleJSON); sprite.reset(); - assert(style); + if (!style) { + style = std::make_shared<Style>(); + } style->loadJSON((const uint8_t *)styleJSON.c_str()); + if (!fileSource) { + fileSource = std::make_shared<FileSource>(**loop, platform::defaultCacheDatabase()); + glyphStore = std::make_shared<GlyphStore>(fileSource); + } fileSource->setBase(base); glyphStore->setURL(util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken())); update(); diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp index e34ed94188..48b46059a5 100644 --- a/src/map/vector_tile_data.cpp +++ b/src/map/vector_tile_data.cpp @@ -30,18 +30,18 @@ void VectorTileData::parse() { return; } -// try { + try { // Parsing creates state that is encapsulated in TileParser. While parsing, // the TileParser object writes results into this objects. All other state // is going to be discarded afterwards. parser->parse(); -// } catch (const std::exception& ex) { -//#if defined(DEBUG) -// fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what()); -//#endif -// cancel(); -// return; -// } + } catch (const std::exception& ex) { +#if defined(DEBUG) + fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what()); +#endif + cancel(); + return; + } if (state != State::obsolete) { state = State::parsed; diff --git a/src/storage/file_source.cpp b/src/storage/file_source.cpp index 370e36f2e0..12d924416c 100644 --- a/src/storage/file_source.cpp +++ b/src/storage/file_source.cpp @@ -10,7 +10,7 @@ namespace mbgl { FileSource::FileSource(uv_loop_t *loop_, const std::string &path) : thread_id(uv_thread_self()), - store(util::ptr<SQLiteStore>(new SQLiteStore(loop_, path))), + store(!path.empty() ? util::ptr<SQLiteStore>(new SQLiteStore(loop_, path)) : nullptr), loop(loop_), queue(new uv_messenger_t) { @@ -18,6 +18,7 @@ FileSource::FileSource(uv_loop_t *loop_, const std::string &path) std::unique_ptr<std::function<void()>> fn { reinterpret_cast<std::function<void()> *>(ptr) }; (*fn)(); }); + uv_unref((uv_handle_t *)&queue->async); } FileSource::~FileSource() { diff --git a/src/storage/http_request.cpp b/src/storage/http_request.cpp index 4a35dcc510..1b799d4895 100644 --- a/src/storage/http_request.cpp +++ b/src/storage/http_request.cpp @@ -22,7 +22,11 @@ struct CacheRequestBaton { HTTPRequest::HTTPRequest(ResourceType type_, const std::string &path, uv_loop_t *loop_, util::ptr<SQLiteStore> store_) : BaseRequest(path), thread_id(uv_thread_self()), loop(loop_), store(store_), type(type_) { - startCacheRequest(); + if (store) { + startCacheRequest(); + } else { + startHTTPRequest(nullptr); + } } void HTTPRequest::startCacheRequest() { @@ -159,14 +163,18 @@ void HTTPRequest::handleHTTPResponse(HTTPResponseType responseType, std::unique_ // The request returned data successfully. We retrieved and decoded the data successfully. case HTTPResponseType::Successful: - store->put(path, type, *res); + if (store) { + store->put(path, type, *res); + } response = std::move(res); notify(); break; // The request confirmed that the data wasn't changed. We already have the data. case HTTPResponseType::NotModified: - store->updateExpiration(path, res->expires); + if (store) { + store->updateExpiration(path, res->expires); + } response = std::move(res); notify(); break; diff --git a/src/storage/sqlite_store.cpp b/src/storage/sqlite_store.cpp index 043c62a514..763100f411 100644 --- a/src/storage/sqlite_store.cpp +++ b/src/storage/sqlite_store.cpp @@ -58,7 +58,7 @@ namespace mbgl { SQLiteStore::SQLiteStore(uv_loop_t *loop, const std::string &path) : thread_id(uv_thread_self()), - db(!path.empty() ? std::make_shared<Database>(path.c_str(), ReadWrite | Create) : nullptr) { + db(std::make_shared<Database>(path.c_str(), ReadWrite | Create)) { createSchema(); worker = new uv_worker_t; uv_worker_init(worker, loop, 1, "SQLite"); diff --git a/src/util/uv-worker.c b/src/util/uv-worker.c index f6122879f0..275989a752 100644 --- a/src/util/uv-worker.c +++ b/src/util/uv-worker.c @@ -6,6 +6,7 @@ typedef struct uv__worker_item_s uv__worker_item_t; struct uv__worker_item_s { + uv_worker_t *worker; void *data; uv_worker_cb work_cb; uv_worker_after_cb after_work_cb; @@ -46,8 +47,14 @@ void uv__worker_after(void *ptr) { if (item->work_cb) { // We are finishing a regular work request. - assert(item->after_work_cb); - item->after_work_cb(item->data); + if (item->after_work_cb) { + assert(item->after_work_cb); + item->after_work_cb(item->data); + } + assert(item->worker->active > 0); + if (--item->worker->active == 0) { + uv_unref((uv_handle_t *)&item->worker->msgr->async); + } } else { // This is a worker thread termination. uv__worker_thread_t *worker_thread = (uv__worker_thread_t *)item->data; @@ -73,13 +80,8 @@ void uv__worker_thread_loop(void *ptr) { assert(item->work_cb); item->work_cb(item->data); - if (item->after_work_cb) { - // Trigger the after callback in the main thread. - uv_messenger_send(worker->msgr, item); - } else { - // There is no after work callback, so it wouldn't do anything anyway. - free(item); - } + // Trigger the after callback in the main thread. + uv_messenger_send(worker->msgr, item); } // Make sure to close all other workers too. @@ -97,9 +99,11 @@ int uv_worker_init(uv_worker_t *worker, uv_loop_t *loop, int count, const char * #ifndef NDEBUG worker->thread_id = uv_thread_self(); #endif + worker->loop = loop; worker->name = name; worker->count = 0; worker->close_cb = NULL; + worker->active = 0; worker->msgr = (uv_messenger_t *)malloc(sizeof(uv_messenger_t)); int ret = uv_messenger_init(loop, worker->msgr, uv__worker_after); if (ret < 0) { @@ -133,10 +137,12 @@ void uv_worker_send(uv_worker_t *worker, void *data, uv_worker_cb work_cb, assert(work_cb); uv__worker_item_t *item = (uv__worker_item_t *)malloc(sizeof(uv__worker_item_t)); + item->worker = worker; item->work_cb = work_cb; item->after_work_cb = after_work_cb; item->data = data; uv_chan_send(&worker->chan, item); + worker->active++; } void uv_worker_close(uv_worker_t *worker, uv_worker_close_cb close_cb) { @@ -149,4 +155,8 @@ void uv_worker_close(uv_worker_t *worker, uv_worker_close_cb close_cb) { worker->close_cb = close_cb; uv_chan_send(&worker->chan, NULL); + assert(worker->active >= 0); + if (worker->active++ == 0) { + uv_ref((uv_handle_t *)&worker->msgr->async); + } } diff --git a/test/fixtures/fixture_request.cpp b/test/fixtures/fixture_request.cpp index 7e351ecfac..3f72b890db 100644 --- a/test/fixtures/fixture_request.cpp +++ b/test/fixtures/fixture_request.cpp @@ -1,9 +1,15 @@ -#include <mbgl/platform/platform.hpp> -#include <mbgl/platform/request.hpp> -#include <mbgl/util/uv_detail.hpp> +#include <mbgl/storage/http_request_baton.hpp> +#include <mbgl/storage/file_request_baton.hpp> +#include <mbgl/storage/response.hpp> #include <mbgl/util/url.hpp> +#include <mbgl/util/std.hpp> #include <mbgl/platform/log.hpp> +#include <uv.h> + +#include <cassert> + + const std::string base_directory = []{ std::string fn = __FILE__; fn.erase(fn.find_last_of("/")); @@ -12,95 +18,48 @@ const std::string base_directory = []{ return fn + "/node_modules/mapbox-gl-test-suite/"; }(); - namespace mbgl { -std::shared_ptr<platform::Request> -platform::request_http(const std::string &url, - std::function<void(Response *)> callback, - std::shared_ptr<uv::loop> loop) { - uv_loop_t *l = nullptr; - if (loop) { - l = **loop; - } else { - l = uv_default_loop(); - } +void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &baton) { + assert(uv_thread_self() == baton->thread_id); - std::string clean_url = util::percentDecode(url); + std::string clean_url = util::percentDecode(baton->path); if (clean_url.find("local://") == 0) { clean_url = base_directory + clean_url.substr(8); } - std::shared_ptr<Request> req = std::make_shared<Request>(url, callback, loop); - - int err; - - uv_fs_t open_req; - err = uv_fs_open(l, &open_req, clean_url.c_str(), O_RDONLY, S_IRUSR, nullptr); - uv_fs_req_cleanup(&open_req); - if (err < 0) { - req->res->code = err; - req->res->error_message = uv_strerror(err); - Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err)); - req->complete(); - return req; - } - uv_file fd = err; - - uv_fs_t stat_req; - uv_fs_fstat(l, &stat_req, fd, nullptr); - uv_fs_req_cleanup(&stat_req); - err = uv_fs_fstat(l, &stat_req, fd, nullptr); - if (err < 0) { - req->res->code = err; - req->res->error_message = uv_strerror(err); - Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err)); - req->complete(); - return req; - } - - const uint64_t size = static_cast<const uv_stat_t*>(stat_req.ptr)->st_size; - - - std::string body; - body.resize(size); - uv_buf_t uvbuf = uv_buf_init(const_cast<char *>(body.data()), body.size()); - - uv_fs_t read_req; - err = uv_fs_read(l, &read_req, fd, &uvbuf, 1, 0, nullptr); - uv_fs_req_cleanup(&read_req); - if (err < 0) { - req->res->code = err; - req->res->error_message = uv_strerror(err); - Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err)); - req->complete(); - return req; + baton->response = std::make_unique<Response>(); + FILE *file = fopen(clean_url.c_str(),"rb"); + if (file != NULL) { + fseek(file, 0, SEEK_END); + const size_t size = ftell(file); + fseek(file, 0, SEEK_SET); + baton->response->data.resize(size); + fread(&baton->response->data[0], size, 1, file); + fclose(file); + + baton->response->code = 200; + baton->type = HTTPResponseType::Successful; + } else { + baton->type = HTTPResponseType::PermanentError; + baton->response->code = 404; } + uv_async_send(baton->async); +} - uv_fs_t close_req; - err = uv_fs_close(l, &close_req, fd, nullptr); - uv_fs_req_cleanup(&close_req); - if (err < 0) { - req->res->code = err; - req->res->error_message = uv_strerror(err); - Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err)); - req->complete(); - return req; - } +void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &baton) { + fprintf(stderr, "HTTP request cannot be canceled because it is answered immediately"); + abort(); +} - req->res->body.swap(body); - req->res->code = 200; - Log::Info(Event::HttpRequest, 200, url); - req->complete(); +namespace platform { - return req; +std::string defaultCacheDatabase() { + // Disables the cache. + return ""; } -void platform::cancel_request_http(const std::shared_ptr<Request> &req) { - if (req) { - req->cancelled = true; - } } } |