1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sqlite_vfs/sqlite_database_vfs_file_set.h"
#include <atomic>
#include <memory>
#include <string_view>
#include <utility>
#include "base/check.h"
#include "base/check_op.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/memory/writable_shared_memory_region.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "components/sqlite_vfs/file_type.h"
#include "components/sqlite_vfs/pending_file_set.h"
#include "components/sqlite_vfs/sandboxed_file.h"
#include "sql/database.h"
namespace {
std::atomic<uint64_t> g_file_set_id_generator(0);
// The base name of the virtual database files served by a file set.
constexpr base::FilePath::StringViewType kDbFileName =
FILE_PATH_LITERAL("data");
} // namespace
namespace sqlite_vfs {
// static
std::optional<SqliteVfsFileSet> SqliteVfsFileSet::Bind(
Client client,
PendingFileSet pending_file_set) {
// Write-ahead logging requires single connection.
CHECK(!pending_file_set.wal_file.IsValid() ||
!pending_file_set.shared_lock.IsValid());
// Write-ahead logging requires read-write access.
CHECK(!pending_file_set.wal_file.IsValid() || pending_file_set.read_write);
base::WritableSharedMemoryMapping mapped_shared_lock;
if (pending_file_set.shared_lock.IsValid()) {
mapped_shared_lock = pending_file_set.shared_lock.Map();
if (!mapped_shared_lock.IsValid()) {
return std::nullopt; // Failed to map the shared lock.
}
}
const auto access_rights = pending_file_set.read_write
? SandboxedFile::AccessRights::kReadWrite
: SandboxedFile::AccessRights::kReadOnly;
auto db_file = std::make_unique<SandboxedFile>(
client, FileType::kMainDb, std::move(pending_file_set.db_file),
access_rights, std::move(mapped_shared_lock));
auto journal_file = std::make_unique<SandboxedFile>(
client, FileType::kMainJournal, std::move(pending_file_set.journal_file),
access_rights);
std::unique_ptr<SandboxedFile> wal_file;
if (pending_file_set.wal_file.IsValid()) {
wal_file = std::make_unique<SandboxedFile>(
client, FileType::kWal, std::move(pending_file_set.wal_file),
access_rights);
}
return SqliteVfsFileSet(std::move(db_file), std::move(journal_file),
std::move(wal_file),
std::move(pending_file_set.shared_lock));
}
SqliteVfsFileSet::SqliteVfsFileSet(
std::unique_ptr<SandboxedFile> db_file,
std::unique_ptr<SandboxedFile> journal_file,
std::unique_ptr<SandboxedFile> wal_journal_file,
base::UnsafeSharedMemoryRegion shared_lock)
: shared_lock_(std::move(shared_lock)),
db_file_(std::move(db_file)),
journal_file_(std::move(journal_file)),
wal_journal_file_(std::move(wal_journal_file)),
virtual_fs_path_(base::FilePath::FromASCII(
base::NumberToString(g_file_set_id_generator.fetch_add(1)))),
read_only_(db_file_->access_rights() ==
SandboxedFile::AccessRights::kReadOnly) {
// It makes no sense to have one file writeable and not the other(s).
CHECK_EQ(db_file_->access_rights(), journal_file_->access_rights());
if (wal_journal_file_) {
CHECK_EQ(db_file_->access_rights(), wal_journal_file_->access_rights());
}
// Write-ahead logging requires single connection.
CHECK(!wal_journal_file_ || !shared_lock_.IsValid());
// Write-ahead logging requires read-write access.
CHECK(!wal_journal_file_ ||
db_file_->access_rights() == SandboxedFile::AccessRights::kReadWrite);
}
SqliteVfsFileSet::SqliteVfsFileSet(SqliteVfsFileSet&& other) = default;
SqliteVfsFileSet& SqliteVfsFileSet::operator=(SqliteVfsFileSet&& other) =
default;
SqliteVfsFileSet::~SqliteVfsFileSet() = default;
base::FilePath SqliteVfsFileSet::GetDbVirtualFilePath() const {
return virtual_fs_path_.Append(kDbFileName);
}
base::FilePath SqliteVfsFileSet::GetJournalVirtualFilePath() const {
return sql::Database::JournalPath(GetDbVirtualFilePath());
}
base::FilePath SqliteVfsFileSet::GetWalJournalVirtualFilePath() const {
return sql::Database::WriteAheadLogPath(GetDbVirtualFilePath());
}
// static
std::string_view SqliteVfsFileSet::GetVirtualFileHistogramVariant(
const base::FilePath& virtual_file_path) {
auto base_name = virtual_file_path.BaseName();
if (base_name.value() == kDbFileName) {
return "DbFile";
}
auto db_path = base::FilePath(kDbFileName);
if (base_name == sql::Database::JournalPath(db_path)) {
return "JournalFile";
}
if (base_name == sql::Database::WriteAheadLogPath(db_path)) {
return "WalJournalFile";
}
NOTREACHED();
}
const base::File& SqliteVfsFileSet::GetDbFile() const {
return db_file_->GetFile();
}
const base::File& SqliteVfsFileSet::GetJournalFile() const {
return journal_file_->GetFile();
}
const base::File& SqliteVfsFileSet::GetWalJournalFile() const {
CHECK(wal_journal_mode());
return wal_journal_file_->GetFile();
}
LockState SqliteVfsFileSet::Abandon() {
return db_file_->Abandon();
}
} // namespace sqlite_vfs
|