summaryrefslogtreecommitdiff
path: root/platform/default/mbgl/storage
diff options
context:
space:
mode:
Diffstat (limited to 'platform/default/mbgl/storage')
-rw-r--r--platform/default/mbgl/storage/offline.cpp33
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp195
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp1
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp89
-rw-r--r--platform/default/mbgl/storage/offline_schema.cpp.include2
-rw-r--r--platform/default/mbgl/storage/offline_schema.sql2
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)
);