Commit 00370898 authored by Shubham Aggarwal's avatar Shubham Aggarwal Committed by Commit Bot

Add test coverage for WAL mode in database_unittest

This change makes it so that all tests in database_unittest.cc now run
both with WAL mode on and off. Better test coverage will help us
transition to using WAL mode by default in the future.

Bug: 78507
Change-Id: I116a8151c1ab4919a78657e46df98b26eddb7f11
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2490664
Commit-Queue: Shubham Aggarwal <shuagga@microsoft.com>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821790}
parent 1bfcd597
This diff is collapsed.
...@@ -9,6 +9,7 @@ namespace sql { ...@@ -9,6 +9,7 @@ namespace sql {
namespace test { namespace test {
struct ColumnInfo; struct ColumnInfo;
bool CorruptSizeInHeader(const base::FilePath&);
} // namespace test } // namespace test
// Restricts access to APIs internal to the //sql package. // Restricts access to APIs internal to the //sql package.
...@@ -23,6 +24,7 @@ class InternalApiToken { ...@@ -23,6 +24,7 @@ class InternalApiToken {
friend class DatabaseTestPeer; friend class DatabaseTestPeer;
friend class Recovery; friend class Recovery;
friend struct test::ColumnInfo; friend struct test::ColumnInfo;
friend bool test::CorruptSizeInHeader(const base::FilePath&);
}; };
} // namespace sql } // namespace sql
......
...@@ -10,12 +10,12 @@ ...@@ -10,12 +10,12 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "base/check.h"
#include "base/check_op.h" #include "base/check_op.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/scoped_file.h" #include "base/files/scoped_file.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "sql/database.h" #include "sql/database.h"
#include "sql/sql_features.h"
#include "sql/statement.h" #include "sql/statement.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h" #include "third_party/sqlite/sqlite3.h"
...@@ -71,21 +71,49 @@ void WriteBigEndian(unsigned val, unsigned char* buf, size_t bytes) { ...@@ -71,21 +71,49 @@ void WriteBigEndian(unsigned val, unsigned char* buf, size_t bytes) {
} }
} }
bool IsWalDatabase(const base::FilePath& db_path) {
// The SQLite header is documented at:
// https://www.sqlite.org/fileformat.html#the_database_header
//
// Read the entire header.
constexpr int kHeaderSize = 100;
uint8_t header[kHeaderSize];
base::ReadFile(db_path, reinterpret_cast<char*>(header), sizeof(header));
constexpr int kWriteVersionHeaderOffset = 18;
constexpr int kReadVersionHeaderOffset = 19;
// If the read version is unsupported, we can't rely on our ability to
// interpret anything else in the header.
DCHECK_LE(header[kReadVersionHeaderOffset], 2)
<< "Unsupported SQLite file format";
return header[kWriteVersionHeaderOffset] == 2;
}
} // namespace } // namespace
namespace sql { namespace sql {
namespace test { namespace test {
bool CorruptSizeInHeader(const base::FilePath& db_path) { bool CorruptSizeInHeader(const base::FilePath& db_path) {
// Checkpoint the WAL file in Truncate mode before corrupting to ensure that if (IsWalDatabase(db_path)) {
// any future transaction always touches the DB file and not just the WAL // Checkpoint the WAL file in Truncate mode before corrupting to ensure that
// file. // any future transaction always touches the DB file and not just the WAL
if (base::FeatureList::IsEnabled(sql::features::kEnableWALModeByDefault)) { // file.
base::ScopedAllowBlockingForTesting allow_blocking; base::ScopedAllowBlockingForTesting allow_blocking;
sql::Database db; // TODO: This function doesn't reliably work if connections to the DB are
// still open. Change any uses to ensure that we close all database
// connections before calling this function.
sql::Database db({.exclusive_locking = false, .wal_mode = true});
if (!db.Open(db_path)) if (!db.Open(db_path))
return false; return false;
if (!db.Execute("PRAGMA wal_checkpoint(TRUNCATE)")) int wal_log_size = 0;
int checkpointed_frame_count = 0;
int truncate_result = sqlite3_wal_checkpoint_v2(
db.db(InternalApiToken()), /*zDb=*/nullptr, SQLITE_CHECKPOINT_TRUNCATE,
&wal_log_size, &checkpointed_frame_count);
// A successful checkpoint in truncate mode sets these to zero.
DCHECK(wal_log_size == 0);
DCHECK(checkpointed_frame_count == 0);
if (truncate_result != SQLITE_OK)
return false; return false;
db.Close(); db.Close();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment