blob: f9d93069b54a556073f0765a2adbb1c01bdc4d23 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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 <string>
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/thread_annotations.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:
// 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.
SQLitePersistentStoreBackendBase(
const base::FilePath& path,
std::string 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);
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 RecordPathDoesNotExistProblem() {}
virtual void RecordOpenDBProblem() {}
virtual void RecordDBMigrationProblem() {}
virtual void RecordNewDBFile() {}
virtual void RecordDBLoaded() {}
// 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 |base::nullopt| will cause the initialization process to fail
// and stop.
virtual base::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 std::string histogram_tag_;
// Whether the database has been initialized.
bool initialized_;
// Whether the KillDatabase callback has been scheduled.
bool corruption_detected_;
// 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_;
// 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_;
DISALLOW_COPY_AND_ASSIGN(SQLitePersistentStoreBackendBase);
};
} // namespace net
#endif // NET_EXTRAS_SQLITE_SQLITE_PERSISTENT_STORE_BACKEND_BASE_H_