1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_EXTRAS_SQLITE_SQLITE_PERSISTENT_STORE_BACKEND_BASE_H_ 6 #define NET_EXTRAS_SQLITE_SQLITE_PERSISTENT_STORE_BACKEND_BASE_H_ 7 8 #include <memory> 9 #include <string> 10 11 #include "base/files/file_path.h" 12 #include "base/functional/callback.h" 13 #include "base/functional/callback_forward.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/thread_annotations.h" 16 #include "sql/meta_table.h" 17 #include "third_party/abseil-cpp/absl/types/optional.h" 18 19 namespace base { 20 class Location; 21 class SequencedTaskRunner; 22 } // namespace base 23 24 namespace sql { 25 class Database; 26 class Statement; 27 } // namespace sql 28 29 namespace net { 30 31 // This class handles the initialization and closing of a SQLite database. It 32 // is designed to be shared between a client thread and a background task 33 // runner. 34 // 35 // Subclasses will want to have: 36 // - methods to load the data from the database, which should call 37 // InitializeDatabase() from the background thread to ensure the database has 38 // been initialized before attempting to load data, 39 // - overridden DoMigrateDatabaseSchema() and CreateDatabaseSchema(), 40 // which will be called in the course of initializing the database, 41 // - optionally overridden DoInitializeDatabase() which performs any other 42 // initialization tasks, 43 // - a way to keep track of pending operations in order to commit them 44 // by invoking Commit() on the background thread, e.g. when a certain batch 45 // size is reached or a certain amount of time has passed, 46 // - overridden DoCommit() to actually handle the logic of committing 47 // pending operations to the database, 48 // - optionally overridden Record*() to record the appropriate metrics. 49 class SQLitePersistentStoreBackendBase 50 : public base::RefCountedThreadSafe<SQLitePersistentStoreBackendBase> { 51 public: 52 SQLitePersistentStoreBackendBase(const SQLitePersistentStoreBackendBase&) = 53 delete; 54 SQLitePersistentStoreBackendBase& operator=( 55 const SQLitePersistentStoreBackendBase&) = delete; 56 57 // Posts a task to flush pending operations to the database in the background. 58 // |callback| is run in the foreground when it is done. 59 void Flush(base::OnceClosure callback); 60 61 // Commit any pending operations and close the database. This must be called 62 // before the object is destroyed. 63 void Close(); 64 65 // Set the callback that will be run at the beginning of Commit. 66 void SetBeforeCommitCallback(base::RepeatingClosure callback); 67 68 protected: 69 friend class base::RefCountedThreadSafe<SQLitePersistentStoreBackendBase>; 70 71 // |current_version_number| and |compatible_version_number| must be greater 72 // than 0, as per //sql/meta_table.h. |background_task_runner| should be 73 // non-null. If |enable_exclusive_access| is true then the sqlite3 database 74 // will be opened with exclusive flag. 75 SQLitePersistentStoreBackendBase( 76 const base::FilePath& path, 77 std::string histogram_tag, 78 const int current_version_number, 79 const int compatible_version_number, 80 scoped_refptr<base::SequencedTaskRunner> background_task_runner, 81 scoped_refptr<base::SequencedTaskRunner> client_task_runner, 82 bool enable_exclusive_access); 83 84 virtual ~SQLitePersistentStoreBackendBase(); 85 86 // Initialize the database. Should be called on background thread. Call this 87 // from a subclass' Load method(s) to ensure the database is initialized 88 // before loading data from it. 89 bool InitializeDatabase(); 90 91 // Record metrics on various errors/events that may occur during 92 // initialization. RecordOpenDBProblem()93 virtual void RecordOpenDBProblem() {} RecordDBMigrationProblem()94 virtual void RecordDBMigrationProblem() {} 95 96 // Embedder-specific database upgrade statements. Returns the version number 97 // that the database ends up at, or returns nullopt on error. This is called 98 // during MigrateDatabaseSchema() which is called during InitializeDatabase(), 99 // and returning |absl::nullopt| will cause the initialization process to fail 100 // and stop. 101 virtual absl::optional<int> DoMigrateDatabaseSchema() = 0; 102 103 // Initializes the desired table(s) of the database, e.g. by creating them or 104 // checking that they already exist. Returns whether the tables exist. 105 // |db()| should not be null when this is called. This is called during 106 // InitializeDatabase(), and returning false will cause the initialization 107 // process to fail and stop. 108 virtual bool CreateDatabaseSchema() = 0; 109 110 // Embedder-specific database initialization tasks. Returns whether they were 111 // successful. |db()| should not be null when this is called. 112 // This is called during InitializeDatabase(), and returning false will cause 113 // the initialization process to fail and stop. The default implementation 114 // just returns true. 115 virtual bool DoInitializeDatabase(); 116 117 // Raze and reset the metatable and database, e.g. if errors are encountered 118 // in initialization. 119 void Reset(); 120 121 // Commit pending operations to the database. First runs 122 // |before_commit_callback_|. Should be called on the background thread. 123 void Commit(); 124 125 // Embedder-specific logic to commit pending operations. (This base class has 126 // no notion of pending operations or what to do with them.) 127 virtual void DoCommit() = 0; 128 129 // Post a task to the background task runner. 130 void PostBackgroundTask(const base::Location& origin, base::OnceClosure task); 131 132 // Post a task to the client task runner. 133 void PostClientTask(const base::Location& origin, base::OnceClosure task); 134 db()135 sql::Database* db() { return db_.get(); } meta_table()136 sql::MetaTable* meta_table() { return &meta_table_; } 137 background_task_runner()138 base::SequencedTaskRunner* background_task_runner() { 139 return background_task_runner_.get(); 140 } client_task_runner()141 base::SequencedTaskRunner* client_task_runner() { 142 return client_task_runner_.get(); 143 } 144 145 private: 146 // Ensures that the database is at the current version, upgrading if 147 // necessary. Returns whether it was successful. 148 bool MigrateDatabaseSchema(); 149 150 // Flushes (commits pending operations) on the background runner, and invokes 151 // |callback| on the client thread when done. 152 void FlushAndNotifyInBackground(base::OnceClosure callback); 153 154 // Close the database on the background runner. 155 void DoCloseInBackground(); 156 157 // Error-handling callback. On errors, the error number (and statement, if 158 // available) will be passed to the callback. 159 // Sets |corruption_detected_| and posts a task to the background runner to 160 // kill the database. 161 void DatabaseErrorCallback(int error, sql::Statement* stmt); 162 163 // Kills the database in the case of a catastropic error. 164 void KillDatabase(); 165 166 // The file path where the database is stored. 167 const base::FilePath path_; 168 169 std::unique_ptr<sql::Database> db_; 170 sql::MetaTable meta_table_; 171 172 // The identifying prefix for metrics. 173 const std::string histogram_tag_; 174 175 // Whether the database has been initialized. 176 bool initialized_ = false; 177 178 // Whether the KillDatabase callback has been scheduled. 179 bool corruption_detected_ = false; 180 181 // Current version number of the database. Must be greater than 0. 182 const int current_version_number_; 183 184 // The lowest version of the code that the database can be read by. Must be 185 // greater than 0. 186 const int compatible_version_number_; 187 188 const scoped_refptr<base::SequencedTaskRunner> background_task_runner_; 189 const scoped_refptr<base::SequencedTaskRunner> client_task_runner_; 190 191 // If true, then sqlite will be requested to open the file with exclusive 192 // access. 193 const bool enable_exclusive_access_; 194 195 // Callback to be run before Commit. 196 base::RepeatingClosure before_commit_callback_ 197 GUARDED_BY(before_commit_callback_lock_); 198 // Guards |before_commit_callback_|. 199 base::Lock before_commit_callback_lock_; 200 }; 201 202 } // namespace net 203 204 #endif // NET_EXTRAS_SQLITE_SQLITE_PERSISTENT_STORE_BACKEND_BASE_H_ 205