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 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_EXTRAS_SQLITE_SQLITE_PERSISTENT_STORE_BACKEND_BASE_H_
#define NET_EXTRAS_SQLITE_SQLITE_PERSISTENT_STORE_BACKEND_BASE_H_
#include <memory>
#include <optional>
#include <string>
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/thread_annotations.h"
#include "sql/database.h"
#include "sql/meta_table.h"
namespace base {
class Location;
class SequencedTaskRunner;
} // namespace base
namespace sql {
class Database;
class Statement;
} // namespace sql
namespace net {
// This class handles the initialization and closing of a SQLite database. It
// is designed to be shared between a client thread and a background task
// runner.
//
// Subclasses will want to have:
// - methods to load the data from the database, which should call
// InitializeDatabase() from the background thread to ensure the database has
// been initialized before attempting to load data,
// - overridden DoMigrateDatabaseSchema() and CreateDatabaseSchema(),
// which will be called in the course of initializing the database,
// - optionally overridden DoInitializeDatabase() which performs any other
// initialization tasks,
// - a way to keep track of pending operations in order to commit them
// by invoking Commit() on the background thread, e.g. when a certain batch
// size is reached or a certain amount of time has passed,
// - overridden DoCommit() to actually handle the logic of committing
// pending operations to the database,
// - optionally overridden Record*() to record the appropriate metrics.
class SQLitePersistentStoreBackendBase
: public base::RefCountedThreadSafe<SQLitePersistentStoreBackendBase> {
public:
SQLitePersistentStoreBackendBase(const SQLitePersistentStoreBackendBase&) =
delete;
SQLitePersistentStoreBackendBase& operator=(
const SQLitePersistentStoreBackendBase&) = delete;
// Posts a task to flush pending operations to the database in the background.
// |callback| is run in the foreground when it is done.
void Flush(base::OnceClosure callback);
// Commit any pending operations and close the database. This must be called
// before the object is destroyed.
void Close();
// Set the callback that will be run at the beginning of Commit.
void SetBeforeCommitCallback(base::RepeatingClosure callback);
protected:
friend class base::RefCountedThreadSafe<SQLitePersistentStoreBackendBase>;
// |current_version_number| and |compatible_version_number| must be greater
// than 0, as per //sql/meta_table.h. |background_task_runner| should be
// non-null. If |enable_exclusive_access| is true then the sqlite3 database
// will be opened with exclusive flag.
SQLitePersistentStoreBackendBase(
const base::FilePath& path,
sql::Database::Tag histogram_tag,
const int current_version_number,
const int compatible_version_number,
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
scoped_refptr<base::SequencedTaskRunner> client_task_runner,
bool enable_exclusive_access);
virtual ~SQLitePersistentStoreBackendBase();
// Initialize the database. Should be called on background thread. Call this
// from a subclass' Load method(s) to ensure the database is initialized
// before loading data from it.
bool InitializeDatabase();
// Record metrics on various errors/events that may occur during
// initialization.
virtual void RecordOpenDBProblem() {}
virtual void RecordDBMigrationProblem() {}
// Embedder-specific database upgrade statements. Returns the version number
// that the database ends up at, or returns nullopt on error. This is called
// during MigrateDatabaseSchema() which is called during InitializeDatabase(),
// and returning |std::nullopt| will cause the initialization process to fail
// and stop.
virtual std::optional<int> DoMigrateDatabaseSchema() = 0;
// Initializes the desired table(s) of the database, e.g. by creating them or
// checking that they already exist. Returns whether the tables exist.
// |db()| should not be null when this is called. This is called during
// InitializeDatabase(), and returning false will cause the initialization
// process to fail and stop.
virtual bool CreateDatabaseSchema() = 0;
// Embedder-specific database initialization tasks. Returns whether they were
// successful. |db()| should not be null when this is called.
// This is called during InitializeDatabase(), and returning false will cause
// the initialization process to fail and stop. The default implementation
// just returns true.
virtual bool DoInitializeDatabase();
// Raze and reset the metatable and database, e.g. if errors are encountered
// in initialization.
void Reset();
// Commit pending operations to the database. First runs
// |before_commit_callback_|. Should be called on the background thread.
void Commit();
// Embedder-specific logic to commit pending operations. (This base class has
// no notion of pending operations or what to do with them.)
virtual void DoCommit() = 0;
// Post a task to the background task runner.
void PostBackgroundTask(const base::Location& origin, base::OnceClosure task);
// Post a task to the client task runner.
void PostClientTask(const base::Location& origin, base::OnceClosure task);
sql::Database* db() { return db_.get(); }
sql::MetaTable* meta_table() { return &meta_table_; }
base::SequencedTaskRunner* background_task_runner() {
return background_task_runner_.get();
}
base::SequencedTaskRunner* client_task_runner() {
return client_task_runner_.get();
}
private:
// Ensures that the database is at the current version, upgrading if
// necessary. Returns whether it was successful.
bool MigrateDatabaseSchema();
// Flushes (commits pending operations) on the background runner, and invokes
// |callback| on the client thread when done.
void FlushAndNotifyInBackground(base::OnceClosure callback);
// Close the database on the background runner.
void DoCloseInBackground();
// Error-handling callback. On errors, the error number (and statement, if
// available) will be passed to the callback.
// Sets |corruption_detected_| and posts a task to the background runner to
// kill the database.
void DatabaseErrorCallback(int error, sql::Statement* stmt);
// Kills the database in the case of a catastropic error.
void KillDatabase();
// The file path where the database is stored.
const base::FilePath path_;
std::unique_ptr<sql::Database> db_;
sql::MetaTable meta_table_;
// The identifying prefix for metrics.
const sql::Database::Tag histogram_tag_;
// Whether the database has been initialized.
bool initialized_ = false;
// Whether the KillDatabase callback has been scheduled.
bool corruption_detected_ = false;
// Current version number of the database. Must be greater than 0.
const int current_version_number_;
// The lowest version of the code that the database can be read by. Must be
// greater than 0.
const int compatible_version_number_;
const scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
const scoped_refptr<base::SequencedTaskRunner> client_task_runner_;
// If true, then sqlite will be requested to open the file with exclusive
// access.
const bool enable_exclusive_access_;
// Callback to be run before Commit.
base::RepeatingClosure before_commit_callback_
GUARDED_BY(before_commit_callback_lock_);
// Guards |before_commit_callback_|.
base::Lock before_commit_callback_lock_;
};
} // namespace net
#endif // NET_EXTRAS_SQLITE_SQLITE_PERSISTENT_STORE_BACKEND_BASE_H_
|