From 2326e2d70999327676c8e918b62e0cb409e325ff Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Mon, 21 Oct 2019 18:15:50 +0300 Subject: [PATCH] [core] Enable incremental vacuum for Offline DB Thus we avoid re-creating the whole database and keeping the backup file as it happens on calling VACUUM. --- .../include/mbgl/storage/offline_database.hpp | 1 + .../src/mbgl/storage/offline_database.cpp | 20 +++++-- .../offline_database/no_auto_vacuum.db | Bin 0 -> 61440 bytes test/storage/offline_database.test.cpp | 52 ++++++++++++++++-- 4 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 test/fixtures/offline_database/no_auto_vacuum.db diff --git a/platform/default/include/mbgl/storage/offline_database.hpp b/platform/default/include/mbgl/storage/offline_database.hpp index 96b867eaa63..e599094a6d8 100644 --- a/platform/default/include/mbgl/storage/offline_database.hpp +++ b/platform/default/include/mbgl/storage/offline_database.hpp @@ -108,6 +108,7 @@ class OfflineDatabase : private util::noncopyable { void migrateToVersion6(); void cleanup(); bool disabled(); + void vacuum(); mapbox::sqlite::Statement& getStatement(const char *); diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp index 133e1f79928..5aa5738f41f 100644 --- a/platform/default/src/mbgl/storage/offline_database.cpp +++ b/platform/default/src/mbgl/storage/offline_database.cpp @@ -140,11 +140,12 @@ void OfflineDatabase::removeExisting() { void OfflineDatabase::removeOldCacheTable() { assert(db); db->exec("DROP TABLE IF EXISTS http_cache"); - db->exec("VACUUM"); + vacuum(); } void OfflineDatabase::createSchema() { assert(db); + vacuum(); db->exec("PRAGMA journal_mode = DELETE"); db->exec("PRAGMA synchronous = FULL"); mapbox::sqlite::Transaction transaction(*db); @@ -155,7 +156,7 @@ void OfflineDatabase::createSchema() { void OfflineDatabase::migrateToVersion3() { assert(db); - db->exec("VACUUM"); + vacuum(); db->exec("PRAGMA user_version = 3"); } @@ -181,6 +182,15 @@ void OfflineDatabase::migrateToVersion6() { transaction.commit(); } +void OfflineDatabase::vacuum() { + if (getPragma("PRAGMA auto_vacuum") != 2 /*INCREMENTAL*/) { + db->exec("PRAGMA auto_vacuum = INCREMENTAL"); + db->exec("VACUUM"); + } else { + db->exec("PRAGMA incremental_vacuum"); + } +} + mapbox::sqlite::Statement& OfflineDatabase::getStatement(const char* sql) { if (!db) { initialize(); @@ -683,7 +693,7 @@ std::exception_ptr OfflineDatabase::clearAmbientCache() try { resourceQuery.run(); - db->exec("VACUUM"); + vacuum(); return nullptr; } catch (const mapbox::sqlite::Exception& ex) { @@ -871,7 +881,7 @@ std::exception_ptr OfflineDatabase::deleteRegion(OfflineRegion&& region) try { evict(0); assert(db); - db->exec("VACUUM"); + vacuum(); // Ensure that the cached offlineTileCount value is recalculated. offlineMapboxTileCount = {}; @@ -1218,7 +1228,7 @@ std::exception_ptr OfflineDatabase::setMaximumAmbientCacheSize(uint64_t size) { if (databaseSize > maximumAmbientCacheSize) { evict(0); - db->exec("VACUUM"); + vacuum(); } return nullptr; diff --git a/test/fixtures/offline_database/no_auto_vacuum.db b/test/fixtures/offline_database/no_auto_vacuum.db new file mode 100644 index 0000000000000000000000000000000000000000..f19e6399332e952f589fa6820b5a4f7a12604c3d GIT binary patch literal 61440 zcmeI&Z*SU09Kdnhq?kY;kvho_`XHxmNT8Bw(Nyixw2{QEqEgZlkP>Yg@`BS^<6kjM zw9}-~YJ0kedk1?bdo9!6!5;4J;5-w^Dph+j>x%@~cjxon=l8S2$vJyk3&y^<8jO10 zSbUP&O<7jz3n5ae)P{WT$hUdr8elr(^r;HaAiqefVR3=dV=3{w-Cw+WEck z-gYtnXYQBmm$~}Z!|eN+KQg~&c4Z|m1Q0*~0R#}ZCh)vqJNJv$Y$ND*{OQPl77Y6B zanSWc{n-vW@v@zxhFfjA;-r4;o{M;mX`MZ-FO`du>P&W1o^9rB$KAJPAH+{J^25Po zbSY0~w*EP#DG3YfP8-$6kBpr@suv}*sfJPCPCI4C`c@BOK2h&doY%=9u!=xwLbzXMMkzl$njGH>VD_m->y0+os`s zk8fue-8ZX;HTPNsvcePu9T~c&`_OHO`e{?tTeX^KxDVWhTR(Eo7OldPWD;_!$8OD) z!9J><9aWFritI*BULyW$CmKj~p$=%(PoB116#<=CL8oH+C}+!`X4B52qLtEg;ft>P zx!Cq5R+RobAJggEj7&RCeS?!} zqmnjT{ydX*&i3D8Wey43#w#k>n%zm;&fUA#?1z|HIHwBjHA10=Sr_aljg!aK#)Wv~ zUWjU|d3sWphd*}fO*NB_e--qDvAm6lrh6`PY>{X4y6|!o40YvU?es8PepB7F9mlbL z_VlQ9?&y!(OC!=n?>3&vsM{X~mI&-C!LlhhCjNbOt>dPCWPyg!*fB2#&VKB%^8P4Tg6 zXznB{%~WM?5{~61^_|xZI!a>YHn7x{xoqQj6%oU#h*uRct%#R0HOsft&S%a|si{NP zKG0w3CmU(!-aYF=2YYeFhyII+--iPgwEX%j%Xaqmte@;f zS}*RPQR3fP>L)6G=VV&VA@!$Z#Z#I8-$O5BdvGi5xO+FnHquo0n+3dD+h^2|jJ*2T zRUf<%KmY**5I_I{1Q0*~0R#|0AgKabH8IxzNewUaLI42-5I_I{1Q0*~0R#|0Knw8v zpF}_a0R#|0009ILKmY**5I`XL0<8a&A7f^S00IagfB*srAbhqv^)R+ literal 0 HcmV?d00001 diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 24234b06246..7b5255c9f5d 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -92,6 +92,14 @@ static std::vector databaseTableColumns(const std::string& path, co return columns; } +static int databaseAutoVacuum(const std::string& path) { + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{db, "pragma auto_vacuum"}; + mapbox::sqlite::Query query{stmt}; + query.run(); + return query.get(0); +} + namespace fixture { const Resource resource{ Resource::Style, "mapbox://test" }; @@ -1360,13 +1368,45 @@ TEST(OfflineDatabase, MigrateFromV5Schema) { EXPECT_EQ(6, databaseUserVersion(filename)); - EXPECT_EQ((std::vector{ "id", "url_template", "pixel_ratio", "z", "x", "y", - "expires", "modified", "etag", "data", "compressed", - "accessed", "must_revalidate" }), + EXPECT_EQ((std::vector{"id", + "url_template", + "pixel_ratio", + "z", + "x", + "y", + "expires", + "modified", + "etag", + "data", + "compressed", + "accessed", + "must_revalidate"}), databaseTableColumns(filename, "tiles")); - EXPECT_EQ((std::vector{ "id", "url", "kind", "expires", "modified", "etag", "data", - "compressed", "accessed", "must_revalidate" }), - databaseTableColumns(filename, "resources")); + EXPECT_EQ( + (std::vector{ + "id", "url", "kind", "expires", "modified", "etag", "data", "compressed", "accessed", "must_revalidate"}), + databaseTableColumns(filename, "resources")); + + EXPECT_EQ(0u, log.uncheckedCount()); +} + +TEST(OfflineDatabase, IncrementalVacuum) { + FixtureLog log; + deleteDatabaseFiles(); + util::copyFile(filename, "test/fixtures/offline_database/no_auto_vacuum.db"); + EXPECT_EQ(0, databaseAutoVacuum(filename)); + + { + OfflineDatabase db(filename); + db.setMaximumAmbientCacheSize(0); + + auto regions = db.listRegions().value(); + for (auto& region : regions) { + db.deleteRegion(std::move(region)); + } + } + + EXPECT_EQ(2, databaseAutoVacuum(filename)); EXPECT_EQ(0u, log.uncheckedCount()); }