1 // Copyright 2019 The Chromium Authors. All rights reserved. 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 COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_DOM_STORAGE_DATABASE_H_ 6 #define COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_DOM_STORAGE_DATABASE_H_ 7 8 #include <stdint.h> 9 10 #include <memory> 11 #include <string> 12 #include <vector> 13 14 #include "base/callback.h" 15 #include "base/containers/span.h" 16 #include "base/files/file_path.h" 17 #include "base/macros.h" 18 #include "base/memory/scoped_refptr.h" 19 #include "base/optional.h" 20 #include "base/sequence_checker.h" 21 #include "base/sequenced_task_runner.h" 22 #include "base/threading/sequence_bound.h" 23 #include "base/trace_event/memory_allocator_dump_guid.h" 24 #include "base/trace_event/memory_dump_provider.h" 25 #include "third_party/leveldatabase/env_chromium.h" 26 #include "third_party/leveldatabase/src/include/leveldb/db.h" 27 #include "third_party/leveldatabase/src/include/leveldb/env.h" 28 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 29 30 namespace storage { 31 32 // Wraps its own leveldb::DB instance on behalf of the DOM Storage backend 33 // implementation. This object is not sequence-safe and must be instantiated on 34 // a sequence which allows use of blocking file operations. 35 // 36 // Use the static |OpenInMemory()| or |OpenDirectory()| helpers to 37 // asynchronously create an instance of this type from any sequence. 38 // When owning a SequenceBound<DomStorageDatabase> as produced by these helpers, 39 // all work on the DomStorageDatabase can be safely done via 40 // |SequenceBound::PostTaskWithThisObject|. 41 class DomStorageDatabase : private base::trace_event::MemoryDumpProvider { 42 public: 43 using Key = std::vector<uint8_t>; 44 using KeyView = base::span<const uint8_t>; 45 using Value = std::vector<uint8_t>; 46 using ValueView = base::span<const uint8_t>; 47 using Status = leveldb::Status; 48 49 // Callback used for basic async operations on this class. 50 using StatusCallback = base::OnceCallback<void(Status)>; 51 52 struct KeyValuePair { 53 KeyValuePair(); 54 KeyValuePair(KeyValuePair&&); 55 KeyValuePair(const KeyValuePair&); 56 KeyValuePair(Key key, Value value); 57 ~KeyValuePair(); 58 KeyValuePair& operator=(KeyValuePair&&); 59 KeyValuePair& operator=(const KeyValuePair&); 60 61 bool operator==(const KeyValuePair& rhs) const; 62 63 Key key; 64 Value value; 65 }; 66 67 ~DomStorageDatabase() override; 68 69 // Callback invoked asynchronously with the result of both |OpenDirectory()| 70 // and |OpenInMemory()| defined below. Includes both the status and the 71 // (possibly null, on failure) sequence-bound DomStorageDatabase instance. 72 using OpenCallback = 73 base::OnceCallback<void(base::SequenceBound<DomStorageDatabase> database, 74 leveldb::Status status)>; 75 76 // Creates a DomStorageDatabase instance for a persistent database within a 77 // filesystem directory given by |directory|, which must be an absolute path. 78 // The database may or may not already exist at this path, and whether or not 79 // this operation succeeds in either case depends on options set in |options|, 80 // e.g. |create_if_missing| and/or |error_if_exists|. 81 // 82 // The instance will be bound to and perform all operations on |task_runner|, 83 // which must support blocking operations. |callback| is called on the calling 84 // sequence once the operation completes. 85 static void OpenDirectory( 86 const base::FilePath& directory, 87 const std::string& name, 88 const leveldb_env::Options& options, 89 const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& 90 memory_dump_id, 91 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, 92 OpenCallback callback); 93 94 // Creates a DomStorageDatabase instance for a new in-memory database. 95 // 96 // The instance will be bound to and perform all operations on |task_runner|, 97 // which must support blocking operations. |callback| is called on the calling 98 // sequence once the operation completes. 99 static void OpenInMemory( 100 const std::string& name, 101 const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& 102 memory_dump_id, 103 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, 104 OpenCallback callback); 105 106 // Destroys the persistent database named |name| within the filesystem 107 // directory identified by the absolute path in |directory|. 108 // 109 // All work is done on |task_runner|, which must support blocking operations, 110 // and upon completion |callback| is called on the calling sequence. 111 static void Destroy( 112 const base::FilePath& directory, 113 const std::string& name, 114 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, 115 StatusCallback callback); 116 117 // Retrieves the value for |key| in the database. 118 Status Get(KeyView key, Value* out_value) const; 119 120 // Sets the database entry for |key| to |value|. 121 Status Put(KeyView key, ValueView value) const; 122 123 // Deletes the database entry for |key|. 124 Status Delete(KeyView key) const; 125 126 // Gets all database entries whose key starts with |prefix|. 127 Status GetPrefixed(KeyView prefix, std::vector<KeyValuePair>* entries) const; 128 129 // Adds operations to |batch| which will delete all database entries whose key 130 // starts with |prefix| when committed. 131 Status DeletePrefixed(KeyView prefix, leveldb::WriteBatch* batch) const; 132 133 // Adds operations to |batch| which when committed will copy all database 134 // entries whose key starts with |prefix| over to new entries with |prefix| 135 // replaced by |new_prefix| in each new key. 136 Status CopyPrefixed(KeyView prefix, 137 KeyView new_prefix, 138 leveldb::WriteBatch* batch) const; 139 140 // Commits operations in |batch| to the database. 141 Status Commit(leveldb::WriteBatch* batch) const; 142 143 // Rewrites the database on disk to clean up traces of deleted entries. 144 // 145 // NOTE: If |RewriteDB()| fails, this DomStorageDatabase may no longer be 146 // usable; in such cases, all future operations will return an IOError status. 147 Status RewriteDB(); 148 SetDestructionCallbackForTesting(base::OnceClosure callback)149 void SetDestructionCallbackForTesting(base::OnceClosure callback) { 150 destruction_callback_ = std::move(callback); 151 } 152 MakeAllCommitsFailForTesting()153 void MakeAllCommitsFailForTesting() { fail_commits_for_testing_ = true; } 154 155 private: 156 friend class base::SequenceBound<DomStorageDatabase>; 157 158 // Constructs a new DomStorageDatabase, creating or opening persistent 159 // on-filesystem database as specified. Asynchronously invokes |callback| on 160 // |callback_task_runner| when done. 161 // 162 // This must be called on a sequence that allows blocking operations. Prefer 163 // to instead call one of the static methods defined below, which can be 164 // called from any sequence. 165 DomStorageDatabase( 166 const base::FilePath& directory, 167 const std::string& name, 168 const leveldb_env::Options& options, 169 const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& 170 memory_dump_id, 171 scoped_refptr<base::SequencedTaskRunner> callback_task_runner, 172 StatusCallback callback); 173 174 // Same as above, but for an in-memory database. |tracking_name| is used 175 // internally for memory dump details. 176 DomStorageDatabase( 177 const std::string& tracking_name, 178 const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& 179 memory_dump_id, 180 scoped_refptr<base::SequencedTaskRunner> callback_task_runner, 181 StatusCallback callback); 182 183 DomStorageDatabase( 184 const std::string& name, 185 std::unique_ptr<leveldb::Env> env, 186 const leveldb_env::Options& options, 187 const base::Optional<base::trace_event::MemoryAllocatorDumpGuid> 188 memory_dump_id_, 189 scoped_refptr<base::SequencedTaskRunner> callback_task_runner, 190 StatusCallback callback); 191 192 // base::trace_event::MemoryDumpProvider implementation: 193 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, 194 base::trace_event::ProcessMemoryDump* pmd) override; 195 196 const std::string name_; 197 const std::unique_ptr<leveldb::Env> env_; 198 const leveldb_env::Options options_; 199 const base::Optional<base::trace_event::MemoryAllocatorDumpGuid> 200 memory_dump_id_; 201 std::unique_ptr<leveldb::DB> db_; 202 203 // Causes all calls to |Commit()| to fail with an IOError for simulated 204 // disk failures in testing. 205 bool fail_commits_for_testing_ = false; 206 207 // Callback to run on destruction in tests. 208 base::OnceClosure destruction_callback_; 209 210 SEQUENCE_CHECKER(sequence_checker_); 211 212 DISALLOW_COPY_AND_ASSIGN(DomStorageDatabase); 213 }; 214 215 } // namespace storage 216 217 #endif // COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_DOM_STORAGE_DATABASE_H_ 218