diff options
Diffstat (limited to 'platform/default/src/mbgl/storage')
-rw-r--r-- | platform/default/src/mbgl/storage/default_file_source.cpp | 6 | ||||
-rw-r--r-- | platform/default/src/mbgl/storage/offline_database.cpp | 139 |
2 files changed, 109 insertions, 36 deletions
diff --git a/platform/default/src/mbgl/storage/default_file_source.cpp b/platform/default/src/mbgl/storage/default_file_source.cpp index e6cdb411bb..2d96a5a9a2 100644 --- a/platform/default/src/mbgl/storage/default_file_source.cpp +++ b/platform/default/src/mbgl/storage/default_file_source.cpp @@ -182,6 +182,8 @@ public: onlineFileSource.setOnlineStatus(status); } + void reopenDatabaseReadOnlyForTesting() { offlineDatabase->reopenDatabaseReadOnlyForTesting(); } + void setMaximumConcurrentRequests(uint32_t maximumConcurrentRequests_) { onlineFileSource.setMaximumConcurrentRequests(maximumConcurrentRequests_); } @@ -385,6 +387,10 @@ void DefaultFileSource::setOnlineStatus(const bool status) { impl->actor().invoke(&Impl::setOnlineStatus, status); } +void DefaultFileSource::reopenDatabaseReadOnlyForTesting() { + impl->actor().invoke(&Impl::reopenDatabaseReadOnlyForTesting); +} + void DefaultFileSource::setMaximumConcurrentRequests(uint32_t maximumConcurrentRequests_) { impl->actor().invoke(&Impl::setMaximumConcurrentRequests, maximumConcurrentRequests_); } diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp index 974815191b..695bbd82f5 100644 --- a/platform/default/src/mbgl/storage/offline_database.cpp +++ b/platform/default/src/mbgl/storage/offline_database.cpp @@ -31,6 +31,15 @@ void OfflineDatabase::initialize() { assert(!db); assert(statements.empty()); + if (readOnly) { + db = std::make_unique<mapbox::sqlite::Database>(mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly)); + + db->setBusyTimeout(Milliseconds::max()); + db->exec("PRAGMA foreign_keys = ON"); + + return; + } + db = std::make_unique<mapbox::sqlite::Database>( mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate)); db->setBusyTimeout(Milliseconds::max()); @@ -153,12 +162,16 @@ void OfflineDatabase::removeExisting() { void OfflineDatabase::removeOldCacheTable() { assert(db); + assert(!readOnly); + db->exec("DROP TABLE IF EXISTS http_cache"); if (autopack) vacuum(); } void OfflineDatabase::createSchema() { assert(db); + assert(!readOnly); + vacuum(); db->exec("PRAGMA journal_mode = DELETE"); db->exec("PRAGMA synchronous = FULL"); @@ -170,6 +183,8 @@ void OfflineDatabase::createSchema() { void OfflineDatabase::migrateToVersion3() { assert(db); + assert(!readOnly); + vacuum(); db->exec("PRAGMA user_version = 3"); } @@ -182,6 +197,8 @@ void OfflineDatabase::migrateToVersion3() { void OfflineDatabase::migrateToVersion5() { assert(db); + assert(!readOnly); + db->exec("PRAGMA journal_mode = DELETE"); db->exec("PRAGMA synchronous = FULL"); db->exec("PRAGMA user_version = 5"); @@ -189,6 +206,8 @@ void OfflineDatabase::migrateToVersion5() { void OfflineDatabase::migrateToVersion6() { assert(db); + assert(!readOnly); + 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"); @@ -198,6 +217,8 @@ void OfflineDatabase::migrateToVersion6() { void OfflineDatabase::vacuum() { assert(db); + assert(!readOnly); + if (getPragma<int64_t>("PRAGMA auto_vacuum") != 2 /*INCREMENTAL*/) { db->exec("PRAGMA auto_vacuum = INCREMENTAL"); db->exec("VACUUM"); @@ -248,6 +269,8 @@ optional<int64_t> OfflineDatabase::hasInternal(const Resource& resource) { } std::pair<bool, uint64_t> OfflineDatabase::put(const Resource& resource, const Response& response) try { + assert(!readOnly); + if (!db) { initialize(); } @@ -266,6 +289,8 @@ std::pair<bool, uint64_t> OfflineDatabase::put(const Resource& resource, const R } std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource, const Response& response, bool evict_) { + assert(!readOnly); + if (response.error) { return { false, 0 }; } @@ -303,19 +328,20 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource, optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resource& resource) { // Update accessed timestamp used for LRU eviction. - try { - mapbox::sqlite::Query accessedQuery{ getStatement("UPDATE resources SET accessed = ?1 WHERE url = ?2") }; - accessedQuery.bind(1, util::now()); - accessedQuery.bind(2, resource.url); - accessedQuery.run(); - } catch (const mapbox::sqlite::Exception& ex) { - if (ex.code == mapbox::sqlite::ResultCode::NotADB || - ex.code == mapbox::sqlite::ResultCode::Corrupt) { - throw; - } + if (!readOnly) { + try { + mapbox::sqlite::Query accessedQuery{getStatement("UPDATE resources SET accessed = ?1 WHERE url = ?2")}; + accessedQuery.bind(1, util::now()); + accessedQuery.bind(2, resource.url); + accessedQuery.run(); + } catch (const mapbox::sqlite::Exception& ex) { + if (ex.code == mapbox::sqlite::ResultCode::NotADB || ex.code == mapbox::sqlite::ResultCode::Corrupt) { + throw; + } - // If we don't have any indication that the database is corrupt, continue as usual. - Log::Warning(Event::Database, static_cast<int>(ex.code), "Can't update timestamp: %s", ex.what()); + // If we don't have any indication that the database is corrupt, continue as usual. + Log::Warning(Event::Database, static_cast<int>(ex.code), "Can't update timestamp: %s", ex.what()); + } } // clang-format off @@ -368,6 +394,8 @@ bool OfflineDatabase::putResource(const Resource& resource, const Response& response, const std::string& data, bool compressed) { + assert(!readOnly); + if (response.notModified) { // clang-format off mapbox::sqlite::Query notModifiedQuery{ getStatement( @@ -451,32 +479,34 @@ bool OfflineDatabase::putResource(const Resource& resource, optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource::TileData& tile) { // Update accessed timestamp used for LRU eviction. - try { - // clang-format off - mapbox::sqlite::Query accessedQuery{ getStatement( - "UPDATE tiles " - "SET accessed = ?1 " - "WHERE url_template = ?2 " - " AND pixel_ratio = ?3 " - " AND x = ?4 " - " AND y = ?5 " - " AND z = ?6 ") }; - // clang-format on + if (!readOnly) { + try { + // clang-format off + mapbox::sqlite::Query accessedQuery{ getStatement( + "UPDATE tiles " + "SET accessed = ?1 " + "WHERE url_template = ?2 " + " AND pixel_ratio = ?3 " + " AND x = ?4 " + " AND y = ?5 " + " AND z = ?6 ") }; + // clang-format on + + accessedQuery.bind(1, util::now()); + accessedQuery.bind(2, tile.urlTemplate); + accessedQuery.bind(3, tile.pixelRatio); + accessedQuery.bind(4, tile.x); + accessedQuery.bind(5, tile.y); + accessedQuery.bind(6, tile.z); + accessedQuery.run(); + } catch (const mapbox::sqlite::Exception& ex) { + if (ex.code == mapbox::sqlite::ResultCode::NotADB || ex.code == mapbox::sqlite::ResultCode::Corrupt) { + throw; + } - accessedQuery.bind(1, util::now()); - accessedQuery.bind(2, tile.urlTemplate); - accessedQuery.bind(3, tile.pixelRatio); - accessedQuery.bind(4, tile.x); - accessedQuery.bind(5, tile.y); - accessedQuery.bind(6, tile.z); - accessedQuery.run(); - } catch (const mapbox::sqlite::Exception& ex) { - if (ex.code == mapbox::sqlite::ResultCode::NotADB || ex.code == mapbox::sqlite::ResultCode::Corrupt) { - throw; + // If we don't have any indication that the database is corrupt, continue as usual. + Log::Warning(Event::Database, static_cast<int>(ex.code), "Can't update timestamp: %s", ex.what()); } - - // If we don't have any indication that the database is corrupt, continue as usual. - Log::Warning(Event::Database, static_cast<int>(ex.code), "Can't update timestamp: %s", ex.what()); } // clang-format off @@ -552,6 +582,8 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, const Response& response, const std::string& data, bool compressed) { + assert(!readOnly); + if (response.notModified) { // clang-format off mapbox::sqlite::Query notModifiedQuery{ getStatement( @@ -652,6 +684,8 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, } std::exception_ptr OfflineDatabase::invalidateAmbientCache() try { + assert(!readOnly); + // clang-format off mapbox::sqlite::Query tileQuery{ getStatement( "UPDATE tiles " @@ -683,6 +717,8 @@ std::exception_ptr OfflineDatabase::invalidateAmbientCache() try { } std::exception_ptr OfflineDatabase::clearAmbientCache() try { + assert(!readOnly); + // clang-format off mapbox::sqlite::Query tileQuery{ getStatement( "DELETE FROM tiles " @@ -714,6 +750,8 @@ std::exception_ptr OfflineDatabase::clearAmbientCache() try { } std::exception_ptr OfflineDatabase::invalidateRegion(int64_t regionID) try { + assert(!readOnly); + { // clang-format off mapbox::sqlite::Query tileQuery{ getStatement( @@ -776,6 +814,8 @@ expected<OfflineRegions, std::exception_ptr> OfflineDatabase::listRegions() try expected<OfflineRegion, std::exception_ptr> OfflineDatabase::createRegion(const OfflineRegionDefinition& definition, const OfflineRegionMetadata& metadata) try { + assert(!readOnly); + // clang-format off mapbox::sqlite::Query query{ getStatement( "INSERT INTO regions (definition, description) " @@ -793,6 +833,8 @@ OfflineDatabase::createRegion(const OfflineRegionDefinition& definition, expected<OfflineRegions, std::exception_ptr> OfflineDatabase::mergeDatabase(const std::string& sideDatabasePath) { + assert(!readOnly); + try { // clang-format off mapbox::sqlite::Query query{ getStatement("ATTACH DATABASE ?1 AS side") }; @@ -869,6 +911,8 @@ OfflineDatabase::mergeDatabase(const std::string& sideDatabasePath) { expected<OfflineRegionMetadata, std::exception_ptr> OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) try { + assert(!readOnly); + // clang-format off mapbox::sqlite::Query query{ getStatement( "UPDATE regions SET description = ?1 " @@ -885,6 +929,8 @@ OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetad } std::exception_ptr OfflineDatabase::deleteRegion(OfflineRegion&& region) try { + assert(!readOnly); + { mapbox::sqlite::Query query{ getStatement("DELETE FROM regions WHERE id = ?") }; query.bind(1, region.getID()); @@ -920,6 +966,8 @@ optional<int64_t> OfflineDatabase::hasRegionResource(const Resource& resource) t uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& resource, const Response& response) try { + assert(!readOnly); + if (!db) { initialize(); } @@ -935,6 +983,8 @@ uint64_t OfflineDatabase::putRegionResource(int64_t regionID, void OfflineDatabase::putRegionResources(int64_t regionID, const std::list<std::tuple<Resource, Response>>& resources, OfflineRegionStatus& status) try { + assert(!readOnly); + if (!db) { initialize(); } @@ -978,6 +1028,8 @@ void OfflineDatabase::putRegionResources(int64_t regionID, } uint64_t OfflineDatabase::putRegionResourceInternal(int64_t regionID, const Resource& resource, const Response& response) { + assert(!readOnly); + uint64_t size = putInternal(resource, response, false).second; bool previouslyUnused = markUsed(regionID, resource); @@ -996,6 +1048,8 @@ uint64_t OfflineDatabase::putRegionResourceInternal(int64_t regionID, const Reso } bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) { + assert(!readOnly); + if (resource.kind == Resource::Kind::Tile) { // clang-format off mapbox::sqlite::Query insertQuery{ getStatement( @@ -1148,6 +1202,8 @@ T OfflineDatabase::getPragma(const char* sql) { // delete an arbitrary number of old cache entries. The free pages approach saves // us from calling VACUUM or keeping a running total, which can be costly. bool OfflineDatabase::evict(uint64_t neededFreeSize) { + assert(!readOnly); + uint64_t pageSize = getPragma<int64_t>("PRAGMA page_size"); uint64_t pageCount = getPragma<int64_t>("PRAGMA page_count"); @@ -1322,4 +1378,15 @@ std::exception_ptr OfflineDatabase::resetDatabase() try { return std::current_exception(); } +void OfflineDatabase::reopenDatabaseReadOnlyForTesting() { + readOnly = true; + + try { + cleanup(); + initialize(); + } catch (...) { + handleError("reopen database read-only"); + } +} + } // namespace mbgl |