• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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