summaryrefslogtreecommitdiff
path: root/chromium/sql/database.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/sql/database.cc
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/sql/database.cc')
-rw-r--r--chromium/sql/database.cc130
1 files changed, 107 insertions, 23 deletions
diff --git a/chromium/sql/database.cc b/chromium/sql/database.cc
index eeab5e626c2..64c7e9cedfe 100644
--- a/chromium/sql/database.cc
+++ b/chromium/sql/database.cc
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <string.h>
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
@@ -241,6 +242,8 @@ Database::Database()
page_size_(kDefaultPageSize),
cache_size_(0),
exclusive_locking_(false),
+ want_wal_mode_(
+ base::FeatureList::IsEnabled(features::kEnableWALModeByDefault)),
transaction_nesting_(0),
needs_rollback_(false),
in_memory_(false),
@@ -813,8 +816,9 @@ bool Database::Raze() {
return false;
}
- const std::string sql = base::StringPrintf("PRAGMA page_size=%d", page_size_);
- if (!null_db.Execute(sql.c_str()))
+ const std::string page_size_sql =
+ base::StringPrintf("PRAGMA page_size=%d", page_size_);
+ if (!null_db.Execute(page_size_sql.c_str()))
return false;
#if defined(OS_ANDROID)
@@ -894,9 +898,39 @@ bool Database::Raze() {
DCHECK_EQ(rc, SQLITE_DONE) << "Failed retrying Raze().";
}
+ // Page size of |db_| and |null_db| differ.
+ if (rc == SQLITE_READONLY) {
+ // Enter TRUNCATE mode to change page size.
+ // TODO(shuagga@microsoft.com): Need a guarantee here that there is no other
+ // database connection open.
+ ignore_result(Execute("PRAGMA journal_mode=TRUNCATE;"));
+ if (!Execute(page_size_sql.c_str())) {
+ return false;
+ }
+ // Page size isn't changed until the database is vacuumed.
+ ignore_result(Execute("VACUUM"));
+ // Re-enter WAL mode.
+ if (UseWALMode()) {
+ ignore_result(Execute("PRAGMA journal_mode=WAL;"));
+ }
+
+ rc = BackupDatabase(null_db.db_, db_, kMain);
+ base::UmaHistogramSparse("Sqlite.RazeDatabase2", rc);
+
+ DCHECK_EQ(rc, SQLITE_DONE) << "Failed retrying Raze().";
+ }
+
// TODO(shess): Figure out which other cases can happen.
DCHECK_EQ(rc, SQLITE_DONE) << "Unable to copy entire null database.";
+ // Checkpoint to propagate transactions to the database file and empty the WAL
+ // file.
+ // The database can still contain old data if the Checkpoint fails so fail the
+ // Raze.
+ if (!CheckpointDatabase()) {
+ return false;
+ }
+
// The entire database should have been backed up.
return rc == SQLITE_DONE;
}
@@ -1449,6 +1483,24 @@ bool Database::OpenInternal(const std::string& file_name,
return false;
}
+ // If indicated, lock up the database before doing anything else, so
+ // that the following code doesn't have to deal with locking.
+ //
+ // Needs to happen before any other operation is performed in WAL mode so that
+ // no operation relies on shared memory if exclusive locking is turned on.
+ //
+ // TODO(shess): This code is brittle. Find the cases where code
+ // doesn't request |exclusive_locking_| and audit that it does the
+ // right thing with SQLITE_BUSY, and that it doesn't make
+ // assumptions about who might change things in the database.
+ // http://crbug.com/56559
+ if (exclusive_locking_) {
+ // TODO(shess): This should probably be a failure. Code which
+ // requests exclusive locking but doesn't get it is almost certain
+ // to be ill-tested.
+ ignore_result(Execute("PRAGMA locking_mode=EXCLUSIVE"));
+ }
+
// Enable extended result codes to provide more color on I/O errors.
// Not having extended result codes is not a fatal problem, as
// Chromium code does not attempt to handle I/O errors anyhow. The
@@ -1480,35 +1532,43 @@ bool Database::OpenInternal(const std::string& file_name,
}
}
- // If indicated, lock up the database before doing anything else, so
- // that the following code doesn't have to deal with locking.
- // TODO(shess): This code is brittle. Find the cases where code
- // doesn't request |exclusive_locking_| and audit that it does the
- // right thing with SQLITE_BUSY, and that it doesn't make
- // assumptions about who might change things in the database.
- // http://crbug.com/56559
- if (exclusive_locking_) {
- // TODO(shess): This should probably be a failure. Code which
- // requests exclusive locking but doesn't get it is almost certain
- // to be ill-tested.
- ignore_result(Execute("PRAGMA locking_mode=EXCLUSIVE"));
- }
+ const base::TimeDelta kBusyTimeout =
+ base::TimeDelta::FromSeconds(kBusyTimeoutSeconds);
+
+ // Needs to happen before entering WAL mode. Will only work if this the first
+ // time the database is being opened in WAL mode.
+ const std::string page_size_sql =
+ base::StringPrintf("PRAGMA page_size=%d", page_size_);
+ ignore_result(ExecuteWithTimeout(page_size_sql.c_str(), kBusyTimeout));
// http://www.sqlite.org/pragma.html#pragma_journal_mode
+ // WAL - Use a write-ahead log instead of a journal file.
// DELETE (default) - delete -journal file to commit.
// TRUNCATE - truncate -journal file to commit.
// PERSIST - zero out header of -journal file to commit.
// TRUNCATE should be faster than DELETE because it won't need directory
// changes for each transaction. PERSIST may break the spirit of using
// secure_delete.
- ignore_result(Execute("PRAGMA journal_mode=TRUNCATE"));
-
- const base::TimeDelta kBusyTimeout =
- base::TimeDelta::FromSeconds(kBusyTimeoutSeconds);
-
- const std::string page_size_sql =
- base::StringPrintf("PRAGMA page_size=%d", page_size_);
- ignore_result(ExecuteWithTimeout(page_size_sql.c_str(), kBusyTimeout));
+ //
+ // Needs to be performed after setting exclusive locking mode. Otherwise can
+ // fail if underlying VFS doesn't support shared memory.
+ if (UseWALMode()) {
+ // Set the synchronous flag to NORMAL. This means that writers don't flush
+ // the WAL file after every write. The WAL file is only flushed on a
+ // checkpoint. In this case, transcations might lose durability on a power
+ // loss (but still durable after an application crash).
+ // TODO(shuagga@microsoft.com): Evaluate if this loss of durability is a
+ // concern.
+ ignore_result(Execute("PRAGMA synchronous=NORMAL"));
+
+ // Opening the db in WAL mode can fail (eg if the underlying VFS doesn't
+ // support shared memory and we are not in exclusive locking mode).
+ //
+ // TODO(shuagga@microsoft.com): We should probably catch a failure here.
+ ignore_result(Execute("PRAGMA journal_mode=WAL"));
+ } else {
+ ignore_result(Execute("PRAGMA journal_mode=TRUNCATE"));
+ }
if (cache_size_ != 0) {
const std::string cache_size_sql =
@@ -1732,4 +1792,28 @@ bool Database::ReportMemoryUsage(base::trace_event::ProcessMemoryDump* pmd,
memory_dump_provider_->ReportMemoryUsage(pmd, dump_name);
}
+bool Database::UseWALMode() const {
+#if defined(OS_FUCHSIA)
+ // WAL mode is only enabled on Fuchsia for databases with exclusive
+ // locking, because this case does not require shared memory support.
+ // At the time this was implemented (May 2020), Fuchsia's shared
+ // memory support was insufficient for SQLite's needs.
+ return want_wal_mode_ && exclusive_locking_;
+#else
+ return want_wal_mode_;
+#endif // defined(OS_FUCHSIA)
+}
+
+bool Database::CheckpointDatabase() {
+ base::Optional<base::ScopedBlockingCall> scoped_blocking_call;
+ InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call);
+
+ static const char* kMainDb = "main";
+ int rc = sqlite3_wal_checkpoint_v2(db_, kMainDb, SQLITE_CHECKPOINT_PASSIVE,
+ /*pnLog=*/nullptr,
+ /*pnCkpt=*/nullptr);
+
+ return rc == SQLITE_OK;
+}
+
} // namespace sql