diff options
Diffstat (limited to 'platform/default/mbgl/storage')
-rw-r--r-- | platform/default/mbgl/storage/offline.cpp | 33 | ||||
-rw-r--r-- | platform/default/mbgl/storage/offline_database.cpp | 195 | ||||
-rw-r--r-- | platform/default/mbgl/storage/offline_database.hpp | 1 | ||||
-rw-r--r-- | platform/default/mbgl/storage/offline_download.cpp | 89 | ||||
-rw-r--r-- | platform/default/mbgl/storage/offline_schema.cpp.include | 2 | ||||
-rw-r--r-- | platform/default/mbgl/storage/offline_schema.sql | 2 |
6 files changed, 197 insertions, 125 deletions
diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp index fd2d47819b..9ec789f725 100644 --- a/platform/default/mbgl/storage/offline.cpp +++ b/platform/default/mbgl/storage/offline.cpp @@ -1,6 +1,7 @@ #include <mbgl/storage/offline.hpp> #include <mbgl/util/tile_cover.hpp> #include <mbgl/util/tileset.hpp> +#include <mbgl/util/projection.hpp> #include <rapidjson/document.h> #include <rapidjson/stringbuffer.h> @@ -24,17 +25,11 @@ OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition( } std::vector<CanonicalTileID> OfflineTilePyramidRegionDefinition::tileCover(SourceType type, uint16_t tileSize, const Range<uint8_t>& zoomRange) const { - double minZ = std::max<double>(util::coveringZoomLevel(minZoom, type, tileSize), zoomRange.min); - double maxZ = std::min<double>(util::coveringZoomLevel(maxZoom, type, tileSize), zoomRange.max); - - assert(minZ >= 0); - assert(maxZ >= 0); - assert(minZ < std::numeric_limits<uint8_t>::max()); - assert(maxZ < std::numeric_limits<uint8_t>::max()); + const Range<uint8_t> clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange); std::vector<CanonicalTileID> result; - for (uint8_t z = minZ; z <= maxZ; z++) { + for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { for (const auto& tile : util::tileCover(bounds, z)) { result.emplace_back(tile.canonical); } @@ -43,6 +38,28 @@ std::vector<CanonicalTileID> OfflineTilePyramidRegionDefinition::tileCover(Sourc return result; } +uint64_t OfflineTilePyramidRegionDefinition::tileCount(SourceType type, uint16_t tileSize, const Range<uint8_t>& zoomRange) const { + + const Range<uint8_t> clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange); + unsigned long result = 0;; + for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { + result += util::tileCount(bounds, z, tileSize); + } + + return result; +} + +Range<uint8_t> OfflineTilePyramidRegionDefinition::coveringZoomRange(SourceType type, uint16_t tileSize, const Range<uint8_t>& zoomRange) const { + double minZ = std::max<double>(util::coveringZoomLevel(minZoom, type, tileSize), zoomRange.min); + double maxZ = std::min<double>(util::coveringZoomLevel(maxZoom, type, tileSize), zoomRange.max); + + assert(minZ >= 0); + assert(maxZ >= 0); + assert(minZ < std::numeric_limits<uint8_t>::max()); + assert(maxZ < std::numeric_limits<uint8_t>::max()); + return { static_cast<uint8_t>(minZ), static_cast<uint8_t>(maxZ) }; +} + OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string& region) { rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc; doc.Parse<0>(region.c_str()); diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp index 204ee04c92..65c2097182 100644 --- a/platform/default/mbgl/storage/offline_database.cpp +++ b/platform/default/mbgl/storage/offline_database.cpp @@ -49,7 +49,8 @@ void OfflineDatabase::ensureSchema() { case 2: migrateToVersion3(); // fall through case 3: // no-op and fall through case 4: migrateToVersion5(); // fall through - case 5: return; + case 5: migrateToVersion6(); // fall through + case 6: return; default: break; // downgrade, delete the database } @@ -83,7 +84,7 @@ void OfflineDatabase::ensureSchema() { db->exec("PRAGMA journal_mode = DELETE"); db->exec("PRAGMA synchronous = FULL"); db->exec(schema); - db->exec("PRAGMA user_version = 5"); + db->exec("PRAGMA user_version = 6"); } catch (...) { Log::Error(Event::Database, "Unexpected error creating database schema: %s", util::toString(std::current_exception()).c_str()); throw; @@ -126,6 +127,14 @@ void OfflineDatabase::migrateToVersion5() { db->exec("PRAGMA user_version = 5"); } +void OfflineDatabase::migrateToVersion6() { + mapbox::sqlite::Transaction transaction(*db); + db->exec("ALTER TABLE resources ADD COLUMN must_revalidate INTEGER NOT NULL DEFAULT 0"); + db->exec("ALTER TABLE tiles ADD COLUMN must_revalidate INTEGER NOT NULL DEFAULT 0"); + db->exec("PRAGMA user_version = 6"); + transaction.commit(); +} + OfflineDatabase::Statement OfflineDatabase::getStatement(const char * sql) { auto it = statements.find(sql); @@ -188,11 +197,11 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource, if (resource.kind == Resource::Kind::Tile) { assert(resource.tileData); inserted = putTile(*resource.tileData, response, - compressed ? compressedData : *response.data, + compressed ? compressedData : response.data ? *response.data : "", compressed); } else { inserted = putResource(resource, response, - compressed ? compressedData : *response.data, + compressed ? compressedData : response.data ? *response.data : "", compressed); } @@ -211,8 +220,8 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resou // clang-format off Statement stmt = getStatement( - // 0 1 2 3 4 - "SELECT etag, expires, modified, data, compressed " + // 0 1 2 3 4 5 + "SELECT etag, expires, must_revalidate, modified, data, compressed " "FROM resources " "WHERE url = ?"); // clang-format on @@ -226,14 +235,15 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resou Response response; uint64_t size = 0; - response.etag = stmt->get<optional<std::string>>(0); - response.expires = stmt->get<optional<Timestamp>>(1); - response.modified = stmt->get<optional<Timestamp>>(2); + response.etag = stmt->get<optional<std::string>>(0); + response.expires = stmt->get<optional<Timestamp>>(1); + response.mustRevalidate = stmt->get<bool>(2); + response.modified = stmt->get<optional<Timestamp>>(3); - optional<std::string> data = stmt->get<optional<std::string>>(3); + optional<std::string> data = stmt->get<optional<std::string>>(4); if (!data) { response.noContent = true; - } else if (stmt->get<int>(4)) { + } else if (stmt->get<bool>(5)) { response.data = std::make_shared<std::string>(util::decompress(*data)); size = data->length(); } else { @@ -265,14 +275,16 @@ bool OfflineDatabase::putResource(const Resource& resource, // clang-format off Statement update = getStatement( "UPDATE resources " - "SET accessed = ?1, " - " expires = ?2 " - "WHERE url = ?3 "); + "SET accessed = ?1, " + " expires = ?2, " + " must_revalidate = ?3 " + "WHERE url = ?4 "); // clang-format on update->bind(1, util::now()); update->bind(2, response.expires); - update->bind(3, resource.url); + update->bind(3, response.mustRevalidate); + update->bind(4, resource.url); update->run(); return false; } @@ -286,29 +298,31 @@ bool OfflineDatabase::putResource(const Resource& resource, // clang-format off Statement update = getStatement( "UPDATE resources " - "SET kind = ?1, " - " etag = ?2, " - " expires = ?3, " - " modified = ?4, " - " accessed = ?5, " - " data = ?6, " - " compressed = ?7 " - "WHERE url = ?8 "); + "SET kind = ?1, " + " etag = ?2, " + " expires = ?3, " + " must_revalidate = ?4, " + " modified = ?5, " + " accessed = ?6, " + " data = ?7, " + " compressed = ?8 " + "WHERE url = ?9 "); // clang-format on update->bind(1, int(resource.kind)); update->bind(2, response.etag); update->bind(3, response.expires); - update->bind(4, response.modified); - update->bind(5, util::now()); - update->bind(8, resource.url); + update->bind(4, response.mustRevalidate); + update->bind(5, response.modified); + update->bind(6, util::now()); + update->bind(9, resource.url); if (response.noContent) { - update->bind(6, nullptr); - update->bind(7, false); + update->bind(7, nullptr); + update->bind(8, false); } else { - update->bindBlob(6, data.data(), data.size(), false); - update->bind(7, compressed); + update->bindBlob(7, data.data(), data.size(), false); + update->bind(8, compressed); } update->run(); @@ -319,23 +333,24 @@ bool OfflineDatabase::putResource(const Resource& resource, // clang-format off Statement insert = getStatement( - "INSERT INTO resources (url, kind, etag, expires, modified, accessed, data, compressed) " - "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) "); + "INSERT INTO resources (url, kind, etag, expires, must_revalidate, modified, accessed, data, compressed) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) "); // clang-format on insert->bind(1, resource.url); insert->bind(2, int(resource.kind)); insert->bind(3, response.etag); insert->bind(4, response.expires); - insert->bind(5, response.modified); - insert->bind(6, util::now()); + insert->bind(5, response.mustRevalidate); + insert->bind(6, response.modified); + insert->bind(7, util::now()); if (response.noContent) { - insert->bind(7, nullptr); - insert->bind(8, false); + insert->bind(8, nullptr); + insert->bind(9, false); } else { - insert->bindBlob(7, data.data(), data.size(), false); - insert->bind(8, compressed); + insert->bindBlob(8, data.data(), data.size(), false); + insert->bind(9, compressed); } insert->run(); @@ -366,8 +381,8 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource: // clang-format off Statement stmt = getStatement( - // 0 1 2 3 4 - "SELECT etag, expires, modified, data, compressed " + // 0 1 2, 3, 4, 5 + "SELECT etag, expires, must_revalidate, modified, data, compressed " "FROM tiles " "WHERE url_template = ?1 " " AND pixel_ratio = ?2 " @@ -389,14 +404,15 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource: Response response; uint64_t size = 0; - response.etag = stmt->get<optional<std::string>>(0); - response.expires = stmt->get<optional<Timestamp>>(1); - response.modified = stmt->get<optional<Timestamp>>(2); + response.etag = stmt->get<optional<std::string>>(0); + response.expires = stmt->get<optional<Timestamp>>(1); + response.mustRevalidate = stmt->get<bool>(2); + response.modified = stmt->get<optional<Timestamp>>(3); - optional<std::string> data = stmt->get<optional<std::string>>(3); + optional<std::string> data = stmt->get<optional<std::string>>(4); if (!data) { response.noContent = true; - } else if (stmt->get<int>(4)) { + } else if (stmt->get<bool>(5)) { response.data = std::make_shared<std::string>(util::decompress(*data)); size = data->length(); } else { @@ -440,22 +456,24 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, // clang-format off Statement update = getStatement( "UPDATE tiles " - "SET accessed = ?1, " - " expires = ?2 " - "WHERE url_template = ?3 " - " AND pixel_ratio = ?4 " - " AND x = ?5 " - " AND y = ?6 " - " AND z = ?7 "); + "SET accessed = ?1, " + " expires = ?2, " + " must_revalidate = ?3 " + "WHERE url_template = ?4 " + " AND pixel_ratio = ?5 " + " AND x = ?6 " + " AND y = ?7 " + " AND z = ?8 "); // clang-format on update->bind(1, util::now()); update->bind(2, response.expires); - update->bind(3, tile.urlTemplate); - update->bind(4, tile.pixelRatio); - update->bind(5, tile.x); - update->bind(6, tile.y); - update->bind(7, tile.z); + update->bind(3, response.mustRevalidate); + update->bind(4, tile.urlTemplate); + update->bind(5, tile.pixelRatio); + update->bind(6, tile.x); + update->bind(7, tile.y); + update->bind(8, tile.z); update->run(); return false; } @@ -469,35 +487,37 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, // clang-format off Statement update = getStatement( "UPDATE tiles " - "SET modified = ?1, " - " etag = ?2, " - " expires = ?3, " - " accessed = ?4, " - " data = ?5, " - " compressed = ?6 " - "WHERE url_template = ?7 " - " AND pixel_ratio = ?8 " - " AND x = ?9 " - " AND y = ?10 " - " AND z = ?11 "); + "SET modified = ?1, " + " etag = ?2, " + " expires = ?3, " + " must_revalidate = ?4, " + " accessed = ?5, " + " data = ?6, " + " compressed = ?7 " + "WHERE url_template = ?8 " + " AND pixel_ratio = ?9 " + " AND x = ?10 " + " AND y = ?11 " + " AND z = ?12 "); // clang-format on update->bind(1, response.modified); update->bind(2, response.etag); update->bind(3, response.expires); - update->bind(4, util::now()); - update->bind(7, tile.urlTemplate); - update->bind(8, tile.pixelRatio); - update->bind(9, tile.x); - update->bind(10, tile.y); - update->bind(11, tile.z); + update->bind(4, response.mustRevalidate); + update->bind(5, util::now()); + update->bind(8, tile.urlTemplate); + update->bind(9, tile.pixelRatio); + update->bind(10, tile.x); + update->bind(11, tile.y); + update->bind(12, tile.z); if (response.noContent) { - update->bind(5, nullptr); - update->bind(6, false); + update->bind(6, nullptr); + update->bind(7, false); } else { - update->bindBlob(5, data.data(), data.size(), false); - update->bind(6, compressed); + update->bindBlob(6, data.data(), data.size(), false); + update->bind(7, compressed); } update->run(); @@ -508,8 +528,8 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, // clang-format off Statement insert = getStatement( - "INSERT INTO tiles (url_template, pixel_ratio, x, y, z, modified, etag, expires, accessed, data, compressed) " - "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11) "); + "INSERT INTO tiles (url_template, pixel_ratio, x, y, z, modified, must_revalidate, etag, expires, accessed, data, compressed) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)"); // clang-format on insert->bind(1, tile.urlTemplate); @@ -518,16 +538,17 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, insert->bind(4, tile.y); insert->bind(5, tile.z); insert->bind(6, response.modified); - insert->bind(7, response.etag); - insert->bind(8, response.expires); - insert->bind(9, util::now()); + insert->bind(7, response.mustRevalidate); + insert->bind(8, response.etag); + insert->bind(9, response.expires); + insert->bind(10, util::now()); if (response.noContent) { - insert->bind(10, nullptr); - insert->bind(11, false); + insert->bind(11, nullptr); + insert->bind(12, false); } else { - insert->bindBlob(10, data.data(), data.size(), false); - insert->bind(11, compressed); + insert->bindBlob(11, data.data(), data.size(), false); + insert->bind(12, compressed); } insert->run(); diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp index 57ffcee4eb..91b544a9e0 100644 --- a/platform/default/mbgl/storage/offline_database.hpp +++ b/platform/default/mbgl/storage/offline_database.hpp @@ -64,6 +64,7 @@ private: void removeExisting(); void migrateToVersion3(); void migrateToVersion5(); + void migrateToVersion6(); class Statement { public: diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index 901f996a4f..ff61114888 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -5,8 +5,10 @@ #include <mbgl/storage/response.hpp> #include <mbgl/storage/http_file_source.hpp> #include <mbgl/style/parser.hpp> -#include <mbgl/style/sources/geojson_source_impl.hpp> -#include <mbgl/style/tile_source_impl.hpp> +#include <mbgl/style/sources/vector_source.hpp> +#include <mbgl/style/sources/raster_source.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/image_source.hpp> #include <mbgl/style/conversion/json.hpp> #include <mbgl/style/conversion/tileset.hpp> #include <mbgl/text/glyph.hpp> @@ -19,6 +21,8 @@ namespace mbgl { +using namespace style; + OfflineDownload::OfflineDownload(int64_t id_, OfflineRegionDefinition&& definition_, OfflineDatabase& offlineDatabase_, @@ -71,40 +75,53 @@ OfflineRegionStatus OfflineDownload::getStatus() const { result.requiredResourceCountIsPrecise = true; for (const auto& source : parser.sources) { - SourceType type = source->baseImpl->type; - - switch (type) { - case SourceType::Vector: - case SourceType::Raster: { - style::TileSourceImpl* tileSource = - static_cast<style::TileSourceImpl*>(source->baseImpl.get()); - const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset(); - const uint16_t tileSize = tileSource->getTileSize(); + SourceType type = source->getType(); + auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) { if (urlOrTileset.is<Tileset>()) { result.requiredResourceCount += - definition.tileCover(type, tileSize, urlOrTileset.get<Tileset>().zoomRange).size(); + definition.tileCount(type, tileSize, urlOrTileset.get<Tileset>().zoomRange); } else { result.requiredResourceCount += 1; - const std::string& url = urlOrTileset.get<std::string>(); + const auto& url = urlOrTileset.get<std::string>(); optional<Response> sourceResponse = offlineDatabase.get(Resource::source(url)); if (sourceResponse) { style::conversion::Error error; optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse->data, error); if (tileset) { result.requiredResourceCount += - definition.tileCover(type, tileSize, (*tileset).zoomRange).size(); + definition.tileCount(type, tileSize, (*tileset).zoomRange); } } else { result.requiredResourceCountIsPrecise = false; } } + }; + + switch (type) { + case SourceType::Vector: { + const auto& vectorSource = *source->as<VectorSource>(); + handleTiledSource(vectorSource.getURLOrTileset(), util::tileSize); + break; + } + + case SourceType::Raster: { + const auto& rasterSource = *source->as<RasterSource>(); + handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize()); break; } case SourceType::GeoJSON: { - style::GeoJSONSource* geojsonSource = source->as<style::GeoJSONSource>(); - if (geojsonSource->getURL()) { + const auto& geojsonSource = *source->as<GeoJSONSource>(); + if (geojsonSource.getURL()) { + result.requiredResourceCount += 1; + } + break; + } + + case SourceType::Image: { + const auto& imageSource = *source->as<ImageSource>(); + if (imageSource.getURL()) { result.requiredResourceCount += 1; } break; @@ -138,20 +155,13 @@ void OfflineDownload::activateDownload() { parser.parse(*styleResponse.data); for (const auto& source : parser.sources) { - SourceType type = source->baseImpl->type; - - switch (type) { - case SourceType::Vector: - case SourceType::Raster: { - const style::TileSourceImpl* tileSource = - static_cast<style::TileSourceImpl*>(source->baseImpl.get()); - const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset(); - const uint16_t tileSize = tileSource->getTileSize(); + SourceType type = source->getType(); + auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) { if (urlOrTileset.is<Tileset>()) { queueTiles(type, tileSize, urlOrTileset.get<Tileset>()); } else { - const std::string& url = urlOrTileset.get<std::string>(); + const auto& url = urlOrTileset.get<std::string>(); status.requiredResourceCountIsPrecise = false; status.requiredResourceCount++; requiredSourceURLs.insert(url); @@ -170,15 +180,34 @@ void OfflineDownload::activateDownload() { } }); } + }; + + switch (type) { + case SourceType::Vector: { + const auto& vectorSource = *source->as<VectorSource>(); + handleTiledSource(vectorSource.getURLOrTileset(), util::tileSize); + break; + } + + case SourceType::Raster: { + const auto& rasterSource = *source->as<RasterSource>(); + handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize()); break; } case SourceType::GeoJSON: { - style::GeoJSONSource::Impl* geojsonSource = - static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get()); + const auto& geojsonSource = *source->as<GeoJSONSource>(); + if (geojsonSource.getURL()) { + queueResource(Resource::source(*geojsonSource.getURL())); + } + break; + } - if (geojsonSource->getURL()) { - queueResource(Resource::source(*geojsonSource->getURL())); + case SourceType::Image: { + const auto& imageSource = *source->as<ImageSource>(); + auto imageUrl = imageSource.getURL(); + if (imageUrl && !imageUrl->empty()) { + queueResource(Resource::image(*imageUrl)); } break; } diff --git a/platform/default/mbgl/storage/offline_schema.cpp.include b/platform/default/mbgl/storage/offline_schema.cpp.include index a80c7677e6..41af81e55b 100644 --- a/platform/default/mbgl/storage/offline_schema.cpp.include +++ b/platform/default/mbgl/storage/offline_schema.cpp.include @@ -10,6 +10,7 @@ static const char * schema = " data BLOB,\n" " compressed INTEGER NOT NULL DEFAULT 0,\n" " accessed INTEGER NOT NULL,\n" +" must_revalidate INTEGER NOT NULL DEFAULT 0,\n" " UNIQUE (url)\n" ");\n" "CREATE TABLE tiles (\n" @@ -25,6 +26,7 @@ static const char * schema = " data BLOB,\n" " compressed INTEGER NOT NULL DEFAULT 0,\n" " accessed INTEGER NOT NULL,\n" +" must_revalidate INTEGER NOT NULL DEFAULT 0,\n" " UNIQUE (url_template, pixel_ratio, z, x, y)\n" ");\n" "CREATE TABLE regions (\n" diff --git a/platform/default/mbgl/storage/offline_schema.sql b/platform/default/mbgl/storage/offline_schema.sql index 9df8fa6a89..722b0e0451 100644 --- a/platform/default/mbgl/storage/offline_schema.sql +++ b/platform/default/mbgl/storage/offline_schema.sql @@ -8,6 +8,7 @@ CREATE TABLE resources ( -- Generic table for style, source, s data BLOB, compressed INTEGER NOT NULL DEFAULT 0, accessed INTEGER NOT NULL, + must_revalidate INTEGER NOT NULL DEFAULT 0, UNIQUE (url) ); @@ -24,6 +25,7 @@ CREATE TABLE tiles ( data BLOB, compressed INTEGER NOT NULL DEFAULT 0, accessed INTEGER NOT NULL, + must_revalidate INTEGER NOT NULL DEFAULT 0, UNIQUE (url_template, pixel_ratio, z, x, y) ); |