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
|
// 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 COMPONENTS_OFFLINE_PAGES_TASK_SQL_STORE_BASE_H_
#define COMPONENTS_OFFLINE_PAGES_TASK_SQL_STORE_BASE_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "sql/database.h"
namespace offline_pages {
// Maintains an SQLite database and permits safe access.
// Opens the database only when queried. Automatically closes the database
// if it's not being used.
// This is a base class, and must be overridden to configure the database
// schema.
class SqlStoreBase {
public:
enum class InitializationStatus {
kNotInitialized,
kInProgress,
kSuccess,
kFailure,
};
// Definition of the callback that is going to run the core of the command in
// the |Execute| method.
template <typename T>
using RunCallback = base::OnceCallback<T(sql::Database*)>;
// Definition of the callback used to pass the result back to the caller of
// |Execute| method.
template <typename T>
using ResultCallback = base::OnceCallback<void(T)>;
// Defines inactivity time of DB after which it is going to be closed.
// TODO(crbug.com/40614502): Derive appropriate value in a scientific way.
static constexpr base::TimeDelta kClosingDelay = base::Seconds(20);
// If |file_path| is empty, this constructs an in-memory database.
SqlStoreBase(sql::Database::Tag histogram_tag,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
const base::FilePath& file_path);
SqlStoreBase(const SqlStoreBase&) = delete;
SqlStoreBase& operator=(const SqlStoreBase&) = delete;
virtual ~SqlStoreBase();
// Gets the initialization status of the store.
InitializationStatus initialization_status_for_testing() const {
return initialization_status_;
}
// Executes a |run_callback| on SQL store on the blocking sequence, and posts
// its result back to calling thread through |result_callback|.
// Calling |Execute| when store is kNotInitialized will cause the store
// initialization to start.
// Store initialization status needs to be kSuccess for run_callback to run.
// If initialization fails, |result_callback| is invoked with |default_value|.
template <typename T>
void Execute(RunCallback<T> run_callback,
ResultCallback<T> result_callback,
T default_value) {
ExecuteInternal(
base::BindOnce(&SqlStoreBase::ExecuteAfterInitialized<T>,
weak_ptr_factory_.GetWeakPtr(), std::move(run_callback),
std::move(result_callback), std::move(default_value)));
}
void SetInitializationStatusForTesting(
InitializationStatus initialization_status,
bool reset_db);
protected:
// Returns a function that installs the latest schema to |db| (if necessary),
// and returns whether the database was successfully verified to have the
// current schema. |GetSchemaInitializationFunction| is called on the main
// thread, but the returned function is executed on the blocking sequence.
virtual base::OnceCallback<bool(sql::Database* db)>
GetSchemaInitializationFunction() = 0;
// Optional tracing methods. The derived class may implement tracing events
// with these methods.
// Called on attempt to open the database. |last_closing_time| is the time
// since the last time the database was closed, or null if the database was
// not previously opened since creation of this.
virtual void OnOpenStart(base::TimeTicks last_closing_time) {}
// Called when done attempting to open the database.
virtual void OnOpenDone(bool success) {}
// Called before a task is executed through |Execute()|.
virtual void OnTaskBegin(bool is_initialized) {}
// Called after calling the |run_callback| in |Execute()|.
virtual void OnTaskRunComplete() {}
// Called after calling the |result_callback| in |Execute()|.
virtual void OnTaskReturnComplete() {}
// Called when starting to close the database.
virtual void OnCloseStart(InitializationStatus status_before_close) {}
// Called after closing the database.
virtual void OnCloseComplete() {}
private:
using DatabaseUniquePtr =
std::unique_ptr<sql::Database, base::OnTaskRunnerDeleter>;
void Initialize(base::OnceClosure pending_command);
void InitializeDone(base::OnceClosure pending_command, bool success);
void ExecuteInternal(base::OnceClosure command);
sql::Database* ExecuteBegin();
template <typename T>
void ExecuteAfterInitialized(RunCallback<T> run_callback,
ResultCallback<T> result_callback,
T default_value) {
DCHECK_NE(initialization_status_, InitializationStatus::kNotInitialized);
DCHECK_NE(initialization_status_, InitializationStatus::kInProgress);
sql::Database* db = ExecuteBegin();
if (!db) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(result_callback), std::move(default_value)));
return;
}
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(std::move(run_callback), db),
base::BindOnce(&SqlStoreBase::RescheduleClosing<T>,
weak_ptr_factory_.GetWeakPtr(),
std::move(result_callback)));
}
// Reschedules the closing with a delay. Ensures that |result_callback| is
// called.
template <typename T>
void RescheduleClosing(ResultCallback<T> result_callback, T result) {
RescheduleClosingBefore();
std::move(result_callback).Run(std::move(result));
OnTaskReturnComplete();
}
void RescheduleClosingBefore();
// Internal function initiating the closing.
void CloseInternal();
// Completes the closing. Main purpose is to destroy the db pointer.
void CloseInternalDone(DatabaseUniquePtr db);
// Background thread where all SQL access should be run.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
// Histogram tag for the sqlite database.
sql::Database::Tag histogram_tag_;
// Path to the database on disk. If empty, the database is in memory only.
base::FilePath db_file_path_;
// Database connection.
DatabaseUniquePtr db_;
// Pending commands.
std::vector<base::OnceClosure> pending_commands_;
// State of initialization.
InitializationStatus initialization_status_ =
InitializationStatus::kNotInitialized;
// Time of the last time the store was closed. Kept for metrics reporting.
base::TimeTicks last_closing_time_;
base::WeakPtrFactory<SqlStoreBase> weak_ptr_factory_{this};
base::WeakPtrFactory<SqlStoreBase> closing_weak_ptr_factory_{this};
};
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_TASK_SQL_STORE_BASE_H_
|