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 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
// 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_SERVICES_STORAGE_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
#define COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/sequence_bound.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/types/pass_key.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/env.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
namespace storage {
// Wraps its own leveldb::DB instance on behalf of the DOM Storage backend
// implementation. This object is not sequence-safe and must be instantiated on
// a sequence which allows use of blocking file operations.
//
// Use the static |OpenInMemory()| or |OpenDirectory()| helpers to
// asynchronously create an instance of this type from any sequence.
// When owning a SequenceBound<DomStorageDatabase> as produced by these helpers,
// all work on the DomStorageDatabase can be safely done via
// |SequenceBound::PostTaskWithThisObject|.
class DomStorageDatabase : private base::trace_event::MemoryDumpProvider {
private:
using PassKey = base::PassKey<DomStorageDatabase>;
public:
using Key = std::vector<uint8_t>;
using KeyView = base::span<const uint8_t>;
using Value = std::vector<uint8_t>;
using ValueView = base::span<const uint8_t>;
using Status = leveldb::Status;
// Callback used for basic async operations on this class.
using StatusCallback = base::OnceCallback<void(Status)>;
struct KeyValuePair {
KeyValuePair();
KeyValuePair(KeyValuePair&&);
KeyValuePair(const KeyValuePair&);
KeyValuePair(Key key, Value value);
~KeyValuePair();
KeyValuePair& operator=(KeyValuePair&&);
KeyValuePair& operator=(const KeyValuePair&);
bool operator==(const KeyValuePair& rhs) const;
Key key;
Value value;
};
DomStorageDatabase(const DomStorageDatabase&) = delete;
DomStorageDatabase& operator=(const DomStorageDatabase&) = delete;
~DomStorageDatabase() override;
// Callback invoked asynchronously with the result of both |OpenDirectory()|
// and |OpenInMemory()| defined below. Includes both the status and the
// (possibly null, on failure) sequence-bound DomStorageDatabase instance.
using OpenCallback =
base::OnceCallback<void(base::SequenceBound<DomStorageDatabase> database,
leveldb::Status status)>;
// Creates a DomStorageDatabase instance for a persistent database within a
// filesystem directory given by |directory|, which must be an absolute path.
// The database may or may not already exist at this path, and will be created
// if not.
//
// The instance will be bound to and perform all operations on |task_runner|,
// which must support blocking operations. |callback| is called on the calling
// sequence once the operation completes.
static void OpenDirectory(
const base::FilePath& directory,
const std::string& name,
const std::optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
OpenCallback callback);
// Creates a DomStorageDatabase instance for a new in-memory database.
//
// The instance will be bound to and perform all operations on |task_runner|,
// which must support blocking operations. |callback| is called on the calling
// sequence once the operation completes.
static void OpenInMemory(
const std::string& name,
const std::optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
OpenCallback callback);
// Destroys the persistent database named |name| within the filesystem
// directory identified by the absolute path in |directory|.
//
// All work is done on |task_runner|, which must support blocking operations,
// and upon completion |callback| is called on the calling sequence.
static void Destroy(
const base::FilePath& directory,
const std::string& name,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
StatusCallback callback);
// Retrieves the value for |key| in the database.
Status Get(KeyView key, Value* out_value) const;
// Sets the database entry for |key| to |value|.
Status Put(KeyView key, ValueView value) const;
// Gets all database entries whose key starts with |prefix|.
Status GetPrefixed(KeyView prefix, std::vector<KeyValuePair>* entries) const;
// Adds operations to |batch| which will delete all database entries whose key
// starts with |prefix| when committed.
Status DeletePrefixed(KeyView prefix, leveldb::WriteBatch* batch) const;
// Adds operations to |batch| which when committed will copy all database
// entries whose key starts with |prefix| over to new entries with |prefix|
// replaced by |new_prefix| in each new key.
Status CopyPrefixed(KeyView prefix,
KeyView new_prefix,
leveldb::WriteBatch* batch) const;
// Commits operations in |batch| to the database.
Status Commit(leveldb::WriteBatch* batch) const;
// Rewrites the database on disk to clean up traces of deleted entries.
//
// NOTE: If |RewriteDB()| fails, this DomStorageDatabase may no longer be
// usable; in such cases, all future operations will return an IOError status.
Status RewriteDB();
void SetDestructionCallbackForTesting(base::OnceClosure callback) {
destruction_callback_ = std::move(callback);
}
void MakeAllCommitsFailForTesting() { fail_commits_for_testing_ = true; }
// Use the static factory functions above to construct this class. These
// constructors are only public for the sake of `base::SequenceBound`.
DomStorageDatabase(
PassKey,
const base::FilePath& directory,
const std::string& name,
const std::optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
StatusCallback callback);
DomStorageDatabase(
PassKey,
const std::string& tracking_name,
const std::optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
StatusCallback callback);
private:
// Initializes a new DomStorageDatabase, creating or opening persistent
// on-filesystem database as specified. Asynchronously invokes `callback` on
// `callback_task_runner` when done.
//
// This must be called on a sequence that allows blocking operations.
void Init(scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
StatusCallback callback);
template <typename... Args>
static void CreateSequenceBoundDomStorageDatabase(
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
DomStorageDatabase::OpenCallback callback,
Args&&... args);
// base::trace_event::MemoryDumpProvider implementation:
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
const std::string name_;
const std::unique_ptr<leveldb::Env> env_;
leveldb_env::Options options_;
const std::optional<base::trace_event::MemoryAllocatorDumpGuid>
memory_dump_id_;
std::unique_ptr<leveldb::DB> db_;
// Causes all calls to |Commit()| to fail with an IOError for simulated
// disk failures in testing.
bool fail_commits_for_testing_ = false;
// Callback to run on destruction in tests.
base::OnceClosure destruction_callback_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace storage
#endif // COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
|