summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTore Halset <halset@pvv.ntnu.no>2016-10-17 18:27:07 +0200
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-10-17 09:27:07 -0700
commita4b79ac2892770456b03692c08f619bcc173c597 (patch)
tree11676e523b07156198fa78bdc518548d04a21b86
parent76ed537be59482ac22b19e1e116388aea8c7742b (diff)
downloadqtlocation-mapboxgl-a4b79ac2892770456b03692c08f619bcc173c597.tar.gz
[core] Optimize OfflineDownload::ensureResource (#6707)
Add `OfflineDatabase::hasRegionResource`, for use when the actual contents are not needed by the caller, avoiding IO and decompression costs.
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp57
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp4
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp25
-rw-r--r--test/storage/offline_database.test.cpp53
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;