diff options
-rw-r--r-- | platform/default/mbgl/storage/offline_database.cpp | 57 | ||||
-rw-r--r-- | platform/default/mbgl/storage/offline_database.hpp | 4 | ||||
-rw-r--r-- | platform/default/mbgl/storage/offline_download.cpp | 25 | ||||
-rw-r--r-- | test/storage/offline_database.test.cpp | 53 |
4 files changed, 130 insertions, 9 deletions
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp index b2ed16db56..4bcc9ad711 100644 --- a/platform/default/mbgl/storage/offline_database.cpp +++ b/platform/default/mbgl/storage/offline_database.cpp @@ -151,6 +151,15 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getInternal(const Resou } } +optional<int64_t> OfflineDatabase::hasInternal(const Resource& resource) { + if (resource.kind == Resource::Kind::Tile) { + assert(resource.tileData); + return hasTile(*resource.tileData); + } else { + return hasResource(resource); + } +} + std::pair<bool, uint64_t> OfflineDatabase::put(const Resource& resource, const Response& response) { return putInternal(resource, response, true); } @@ -236,6 +245,19 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resou return std::make_pair(response, size); } +optional<int64_t> OfflineDatabase::hasResource(const Resource& resource) { + // clang-format off + Statement stmt = getStatement("SELECT length(data) FROM resources WHERE url = ?"); + // clang-format on + + stmt->bind(1, resource.url); + if (!stmt->run()) { + return {}; + } + + return stmt->get<optional<int64_t>>(0); +} + bool OfflineDatabase::putResource(const Resource& resource, const Response& response, const std::string& data, @@ -386,6 +408,31 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource: return std::make_pair(response, size); } +optional<int64_t> OfflineDatabase::hasTile(const Resource::TileData& tile) { + // clang-format off + Statement stmt = getStatement( + "SELECT length(data) " + "FROM tiles " + "WHERE url_template = ?1 " + " AND pixel_ratio = ?2 " + " AND x = ?3 " + " AND y = ?4 " + " AND z = ?5 "); + // clang-format on + + stmt->bind(1, tile.urlTemplate); + stmt->bind(2, tile.pixelRatio); + stmt->bind(3, tile.x); + stmt->bind(4, tile.y); + stmt->bind(5, tile.z); + + if (!stmt->run()) { + return {}; + } + + return stmt->get<optional<int64_t>>(0); +} + bool OfflineDatabase::putTile(const Resource::TileData& tile, const Response& response, const std::string& data, @@ -562,6 +609,16 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getRegionResource(int64 return response; } +optional<int64_t> OfflineDatabase::hasRegionResource(int64_t regionID, const Resource& resource) { + auto response = hasInternal(resource); + + if (response) { + markUsed(regionID, resource); + } + + return response; +} + uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& resource, const Response& response) { uint64_t size = putInternal(resource, response, false).second; bool previouslyUnused = markUsed(regionID, resource); diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp index 011817fbee..875677f7cf 100644 --- a/platform/default/mbgl/storage/offline_database.hpp +++ b/platform/default/mbgl/storage/offline_database.hpp @@ -46,6 +46,7 @@ public: // Return value is (response, stored size) optional<std::pair<Response, uint64_t>> getRegionResource(int64_t regionID, const Resource&); + optional<int64_t> hasRegionResource(int64_t regionID, const Resource&); uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&); OfflineRegionDefinition getRegionDefinition(int64_t regionID); @@ -80,14 +81,17 @@ private: Statement getStatement(const char *); optional<std::pair<Response, uint64_t>> getTile(const Resource::TileData&); + optional<int64_t> hasTile(const Resource::TileData&); bool putTile(const Resource::TileData&, const Response&, const std::string&, bool compressed); optional<std::pair<Response, uint64_t>> getResource(const Resource&); + optional<int64_t> hasResource(const Resource&); bool putResource(const Resource&, const Response&, const std::string&, bool compressed); optional<std::pair<Response, uint64_t>> getInternal(const Resource&); + optional<int64_t> hasInternal(const Resource&); std::pair<bool, uint64_t> putInternal(const Resource&, const Response&, bool evict); // Return value is true iff the resource was previously unused by any other regions. diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index 293166b807..9e2e11c86f 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -252,19 +252,26 @@ void OfflineDownload::ensureResource(const Resource& resource, auto workRequestsIt = requests.insert(requests.begin(), nullptr); *workRequestsIt = util::RunLoop::Get()->invokeCancellable([=]() { requests.erase(workRequestsIt); - - optional<std::pair<Response, uint64_t>> offlineResponse = - offlineDatabase.getRegionResource(id, resource); - if (offlineResponse) { - if (callback) { - callback(offlineResponse->first); + + auto getResourceSizeInDatabase = [&] () -> optional<int64_t> { + if (!callback) { + return offlineDatabase.hasRegionResource(id, resource); } - + optional<std::pair<Response, uint64_t>> response = offlineDatabase.getRegionResource(id, resource); + if (!response) { + return {}; + } + callback(response->first); + return response->second; + }; + + optional<int64_t> offlineResponse = getResourceSizeInDatabase(); + if (offlineResponse) { status.completedResourceCount++; - status.completedResourceSize += offlineResponse->second; + status.completedResourceSize += *offlineResponse; if (resource.kind == Resource::Kind::Tile) { status.completedTileCount += 1; - status.completedTileSize += offlineResponse->second; + status.completedTileSize += *offlineResponse; } observer->statusChanged(status); diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index bcc9784b35..2e25835d80 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -496,6 +496,59 @@ TEST(OfflineDatabase, GetRegionCompletedStatus) { EXPECT_EQ(tileSize, status3.completedTileSize); } +TEST(OfflineDatabase, HasRegionResource) { + using namespace mbgl; + + OfflineDatabase db(":memory:", 1024 * 100); + OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); + + EXPECT_FALSE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/1")))); + EXPECT_FALSE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/20")))); + + Response response; + response.data = randomString(1024); + + for (uint32_t i = 1; i <= 100; i++) { + db.putRegionResource(region.getID(), Resource::style("http://example.com/"s + util::toString(i)), response); + } + + EXPECT_TRUE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/1")))); + EXPECT_TRUE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/20")))); + EXPECT_EQ(1024, *(db.hasRegionResource(region.getID(), Resource::style("http://example.com/20")))); +} + +TEST(OfflineDatabase, HasRegionResourceTile) { + using namespace mbgl; + + OfflineDatabase db(":memory:", 1024 * 100); + OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); + + Resource resource { Resource::Tile, "http://example.com/" }; + resource.tileData = Resource::TileData { + "http://example.com/", + 1, + 0, + 0, + 0 + }; + Response response; + + response.data = std::make_shared<std::string>("first"); + + EXPECT_FALSE(bool(db.hasRegionResource(region.getID(), resource))); + db.putRegionResource(region.getID(), resource, response); + EXPECT_TRUE(bool(db.hasRegionResource(region.getID(), resource))); + EXPECT_EQ(5, *(db.hasRegionResource(region.getID(), resource))); + + OfflineRegion anotherRegion = db.createRegion(definition, OfflineRegionMetadata()); + EXPECT_LT(region.getID(), anotherRegion.getID()); + EXPECT_TRUE(bool(db.hasRegionResource(anotherRegion.getID(), resource))); + EXPECT_EQ(5, *(db.hasRegionResource(anotherRegion.getID(), resource))); + +} + TEST(OfflineDatabase, OfflineMapboxTileCount) { using namespace mbgl; |