| // 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_ |