blob: ccb91f46ea3de2d4c9469f17f9b74a67d92dcc8c [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[email protected]72a4183d2013-05-31 18:33:102// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Evan Stade1a8d9d42024-09-10 19:37:195#ifndef CONTENT_BROWSER_INDEXED_DB_INSTANCE_DATABASE_H_
6#define CONTENT_BROWSER_INDEXED_DB_INSTANCE_DATABASE_H_
[email protected]72a4183d2013-05-31 18:33:107
avib7348942015-12-25 20:57:108#include <stddef.h>
9#include <stdint.h>
10
[email protected]907a8bc52013-06-07 16:32:3411#include <map>
jsbell19644202016-07-15 22:27:0812#include <memory>
Abhishek Shanthkumar88ce4902025-06-26 16:00:0013#include <set>
[email protected]d5516bfe2013-07-10 01:31:5614#include <string>
[email protected]f243eacf2014-01-16 23:55:0915#include <utility>
[email protected]72a4183d2013-05-31 18:33:1016#include <vector>
17
Brett Wilsoncc8623d2017-09-12 03:28:1018#include "base/containers/queue.h"
Avi Drissmanadac21992023-01-11 23:46:3919#include "base/functional/callback.h"
dmurph497e676f12017-04-25 20:29:5720#include "base/gtest_prod_util.h"
Keishi Hattori0e45c022021-11-27 09:25:5221#include "base/memory/raw_ptr.h"
[email protected]72a4183d2013-05-31 18:33:1022#include "base/memory/ref_counted.h"
Mingyu Lei0fe8df72022-12-16 06:44:4823#include "base/memory/scoped_refptr.h"
Daniel Murphy4c0f9c12019-05-23 01:14:3524#include "base/memory/weak_ptr.h"
Nathan Memmottaecdf3452022-10-10 17:53:3725#include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h"
Ari Chivukula65a987e2022-04-26 19:04:1226#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
Daniel Murphy0240b782019-08-14 21:15:0927#include "content/browser/indexed_db/indexed_db_value.h"
Evan Staded9529ea52025-04-11 17:02:5028#include "content/browser/indexed_db/instance/backing_store.h"
Evan Stade1a8d9d42024-09-10 19:37:1929#include "content/browser/indexed_db/instance/connection_coordinator.h"
30#include "content/browser/indexed_db/instance/factory_client.h"
31#include "content/browser/indexed_db/instance/pending_connection.h"
[email protected]907a8bc52013-06-07 16:32:3432#include "content/browser/indexed_db/list_set.h"
Daniel Murphyd36cedf2017-10-12 00:04:5433#include "content/common/content_export.h"
Chase Phillips68ecf5512018-08-16 01:59:1334#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
Henrique Ferreiroda0a55c2019-11-12 14:06:0435#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-forward.h"
jsbellbebef322016-04-15 16:46:2036
Chase Phillips850b96f72018-08-24 19:44:1637namespace blink {
Chase Phillips33d161d62018-08-28 19:44:1238class IndexedDBKeyRange;
39struct IndexedDBDatabaseMetadata;
Chase Phillips33d161d62018-08-28 19:44:1240} // namespace blink
Chase Phillips850b96f72018-08-24 19:44:1641
Evan Stadecbb1e002024-09-13 20:06:5742namespace content::indexed_db {
43class BucketContext;
44class Connection;
45class DatabaseCallbacks;
46class Transaction;
Evan Stade6265dcd2024-02-27 20:50:0447enum class CursorType;
Evan Stade6265dcd2024-02-27 20:50:0448
Evan Stade1a8d9d42024-09-10 19:37:1949// This class maps to a single IDB database:
50// https://www.w3.org/TR/IndexedDB/#database
51//
52// It is created and operated on a bucket thread.
Evan Stadecbb1e002024-09-13 20:06:5753class CONTENT_EXPORT Database {
[email protected]72a4183d2013-05-31 18:33:1054 public:
Daniel Murphy4c0f9c12019-05-23 01:14:3555 // Used to report irrecoverable backend errors. The second argument can be
56 // null.
Mike Wasserman0d5da522024-09-27 07:47:0357 using ErrorCallback = base::RepeatingCallback<void(Status, const char*)>;
[email protected]72a4183d2013-05-31 18:33:1058
Abhishek Shanthkumar88ce4902025-06-26 16:00:0059 Database(uint32_t id_for_locks,
60 const std::u16string& name,
61 BucketContext& bucket_context);
Evan Stade6a314fe2023-09-25 21:24:1262
Evan Stadecbb1e002024-09-13 20:06:5763 Database(const Database&) = delete;
64 Database& operator=(const Database&) = delete;
Peter Boström828b9022021-09-21 02:28:4365
Evan Stadecbb1e002024-09-13 20:06:5766 virtual ~Database();
Daniel Murphy4c0f9c12019-05-23 01:14:3567
Evan Stadecbb1e002024-09-13 20:06:5768 BackingStore* backing_store();
Evan Stade2fbd4532025-04-30 10:19:2269 BackingStore::Database* backing_store_db() { return backing_store_db_.get(); }
Evan Stade22f9c2642024-02-04 00:35:2870 PartitionedLockManager& lock_manager();
[email protected]59057f82013-09-11 20:52:2471
Evan Stade2fbd4532025-04-30 10:19:2272 const blink::IndexedDBDatabaseMetadata& metadata() const {
73 return backing_store_db_->GetMetadata();
Ari Chivukula664bf8d2022-04-27 23:28:1874 }
Evan Stade2fbd4532025-04-30 10:19:2275 const std::u16string& name() const { return name_; }
76 int64_t version() const;
77 bool IsInitialized() const;
[email protected]907a8bc52013-06-07 16:32:3478
Evan Stadee2a68162025-07-08 17:22:5479 // Called to permanently delete the database wrapped by `this`. Will call
80 // `on_complete` and release `locks` when done. This may be called more than
81 // once, in which case latter calls are a no-op, and `on_complete` will not be
82 // called. Returns an error, or the latest version of the deleted database
83 // if successful, or 0 if the database had already been deleted.
84 StatusOr<int64_t> DeleteDatabase(std::vector<PartitionedLock> locks,
85 base::OnceClosure on_complete);
86
Abhishek Shanthkumar88ce4902025-06-26 16:00:0087 // Builds the set of lock requests for the given transaction `mode` and
88 // `scope`. `scope` is used iff `mode` is not `VersionChange`.
89 std::vector<PartitionedLockManager::PartitionedLockRequest>
90 BuildLockRequestsForTransaction(blink::mojom::IDBTransactionMode mode,
91 const std::set<int64_t>& scope) const;
92
Evan Stadecbb1e002024-09-13 20:06:5793 const list_set<Connection*>& connections() const { return connections_; }
jsbell7017da42016-08-16 13:07:1594
Evan Stade4c8bfd62025-05-08 15:52:3695 Status RunTasks();
Evan Stadecbb1e002024-09-13 20:06:5796 void RegisterAndScheduleTransaction(Transaction* transaction);
[email protected]907a8bc52013-06-07 16:32:3497
Daniel Murphy4c0f9c12019-05-23 01:14:3598 // The database object (this object) must be kept alive for the duration of
Ari Chivukula8d3ecea2021-06-18 18:55:4899 // this call. This means the caller should own an
Evan Stadecbb1e002024-09-13 20:06:57100 // BucketContextHandle while calling this methods.
Mingyu Lei87210bc2025-04-17 09:35:50101 Status ForceCloseAndRunTasks(const std::string& message);
[email protected]75a854a2014-07-07 15:57:36102
Evan Stadecbb1e002024-09-13 20:06:57103 void ScheduleOpenConnection(std::unique_ptr<PendingConnection> connection);
Mingyu Lei0fe8df72022-12-16 06:44:48104
Evan Stadecbb1e002024-09-13 20:06:57105 void ScheduleDeleteDatabase(std::unique_ptr<FactoryClient> factory_client,
106 base::OnceClosure on_deletion_complete);
Daniel Murphy48b6b3a2019-08-07 20:38:25107
[email protected]8df07d22013-07-22 17:57:43108 // Number of connections that have progressed passed initial open call.
Daniel Murphy7c750432019-08-20 01:39:47109 size_t ConnectionCount() const { return connections_.size(); }
jsbell19644202016-07-15 22:27:08110
111 // Number of active open/delete calls (running or blocked on other
112 // connections).
Daniel Murphyede91592019-08-12 19:50:22113 size_t ActiveOpenDeleteCount() const {
114 return connection_coordinator_.ActiveOpenDeleteCount();
115 }
jsbell19644202016-07-15 22:27:08116
117 // Number of open/delete calls that are waiting their turn.
Daniel Murphyede91592019-08-12 19:50:22118 size_t PendingOpenDeleteCount() const {
119 return connection_coordinator_.PendingOpenDeleteCount();
120 }
[email protected]8df07d22013-07-22 17:57:43121
Mike Wasserman0d5da522024-09-27 07:47:03122 Status VersionChangeOperation(int64_t version, Transaction* transaction);
Daniel Murphy0240b782019-08-14 21:15:09123
Mike Wasserman0d5da522024-09-27 07:47:03124 Status GetOperation(int64_t object_store_id,
125 int64_t index_id,
Evan Stadeca999b12025-05-09 19:09:11126 blink::IndexedDBKeyRange key_range,
Mike Wasserman0d5da522024-09-27 07:47:03127 indexed_db::CursorType cursor_type,
128 blink::mojom::IDBDatabase::GetCallback callback,
129 Transaction* transaction);
Daniel Murphy0240b782019-08-14 21:15:09130
Daniel Murphy0240b782019-08-14 21:15:09131 struct OpenCursorOperationParams {
132 OpenCursorOperationParams();
Peter Boström828b9022021-09-21 02:28:43133
134 OpenCursorOperationParams(const OpenCursorOperationParams&) = delete;
135 OpenCursorOperationParams& operator=(const OpenCursorOperationParams&) =
136 delete;
137
Daniel Murphy0240b782019-08-14 21:15:09138 ~OpenCursorOperationParams();
139 int64_t object_store_id;
140 int64_t index_id;
Evan Stadeca999b12025-05-09 19:09:11141 blink::IndexedDBKeyRange key_range;
Daniel Murphy0240b782019-08-14 21:15:09142 blink::mojom::IDBCursorDirection direction;
143 indexed_db::CursorType cursor_type;
144 blink::mojom::IDBTaskType task_type;
145 blink::mojom::IDBDatabase::OpenCursorCallback callback;
Daniel Murphy0240b782019-08-14 21:15:09146 };
Mike Wasserman0d5da522024-09-27 07:47:03147 Status OpenCursorOperation(std::unique_ptr<OpenCursorOperationParams> params,
148 const storage::BucketLocator& bucket_locator,
149 Transaction* transaction);
Daniel Murphy0240b782019-08-14 21:15:09150
Mike Wasserman0d5da522024-09-27 07:47:03151 Status CountOperation(int64_t object_store_id,
152 int64_t index_id,
Evan Stadeca999b12025-05-09 19:09:11153 blink::IndexedDBKeyRange key_range,
Mike Wasserman0d5da522024-09-27 07:47:03154 blink::mojom::IDBDatabase::CountCallback callback,
155 Transaction* transaction);
Daniel Murphy0240b782019-08-14 21:15:09156
Mike Wasserman0d5da522024-09-27 07:47:03157 Status DeleteRangeOperation(
dmurph50ab051b32016-11-29 22:13:30158 int64_t object_store_id,
Evan Stadeca999b12025-05-09 19:09:11159 blink::IndexedDBKeyRange key_range,
Evan Stadead03d762023-06-01 16:37:58160 blink::mojom::IDBDatabase::DeleteRangeCallback success_callback,
Evan Stadecbb1e002024-09-13 20:06:57161 Transaction* transaction);
Daniel Murphy0240b782019-08-14 21:15:09162
Mike Wasserman0d5da522024-09-27 07:47:03163 Status GetKeyGeneratorCurrentNumberOperation(
Harley Li20add692019-02-15 22:54:12164 int64_t object_store_id,
Evan Stadedc38e9712023-07-14 02:04:54165 blink::mojom::IDBDatabase::GetKeyGeneratorCurrentNumberCallback callback,
Evan Stadecbb1e002024-09-13 20:06:57166 Transaction* transaction);
Daniel Murphy0240b782019-08-14 21:15:09167
Mike Wasserman0d5da522024-09-27 07:47:03168 Status ClearOperation(int64_t object_store_id,
169 blink::mojom::IDBDatabase::ClearCallback callback,
170 Transaction* transaction);
[email protected]65880a82013-08-16 21:30:08171
Evan Stade4202b1f2024-06-12 16:10:54172 // Use this factory function for GetAll instead of creating the operation
173 // directly.
Mike Wasserman0d5da522024-09-27 07:47:03174 base::OnceCallback<Status(Transaction*)> CreateGetAllOperation(
Evan Stadecbb1e002024-09-13 20:06:57175 int64_t object_store_id,
176 int64_t index_id,
Evan Stadeca999b12025-05-09 19:09:11177 blink::IndexedDBKeyRange key_range,
Steve Becker4848af32024-10-29 22:57:19178 blink::mojom::IDBGetAllResultType result_type,
Evan Stadecbb1e002024-09-13 20:06:57179 int64_t max_count,
Steve Becker4848af32024-10-29 22:57:19180 blink::mojom::IDBCursorDirection direction,
Evan Stadecbb1e002024-09-13 20:06:57181 blink::mojom::IDBDatabase::GetAllCallback callback,
182 Transaction* transaction);
Evan Stade4202b1f2024-06-12 16:10:54183
Daniel Murphy0240b782019-08-14 21:15:09184 bool IsObjectStoreIdInMetadata(int64_t object_store_id) const;
Daniel Murphy0240b782019-08-14 21:15:09185 bool IsObjectStoreIdAndMaybeIndexIdInMetadata(int64_t object_store_id,
186 int64_t index_id) const;
Daniel Murphy0240b782019-08-14 21:15:09187
Brad Triebwasserfe45f3f2024-06-03 19:20:29188 // Returns metadata relevant to idb-internals.
189 storage::mojom::IdbDatabaseMetadataPtr GetIdbInternalsMetadata() const;
Brad Triebwasser88b84af2024-06-04 19:36:55190 // Called when the data used to populate the struct in
191 // `GetIdbInternalsMetadata` is changed in a significant way.
192 void NotifyOfIdbInternalsRelevantChange();
Brad Triebwasserfe45f3f2024-06-03 19:20:29193
Evan Stadecbb1e002024-09-13 20:06:57194 base::WeakPtr<Database> AsWeakPtr() { return weak_factory_.GetWeakPtr(); }
Daniel Murphy7c750432019-08-20 01:39:47195
Evan Stadecbb1e002024-09-13 20:06:57196 void AddConnectionForTesting(Connection* connection) {
Evan Stade2fbd4532025-04-30 10:19:22197 if (connections_.empty()) {
198 OpenInternal();
199 }
Daniel Murphy7c750432019-08-20 01:39:47200 connections_.insert(connection);
201 }
Daniel Murphy0240b782019-08-14 21:15:09202
Evan Stade4c8bfd62025-05-08 15:52:36203 bool CanBeDestroyed();
204
jsbell341d5582015-08-27 17:58:27205 protected:
Evan Stadecbb1e002024-09-13 20:06:57206 friend class Transaction;
Evan Stadecbb1e002024-09-13 20:06:57207 friend class ConnectionCoordinator::ConnectionRequest;
208 friend class ConnectionCoordinator::OpenRequest;
209 friend class ConnectionCoordinator::DeleteRequest;
dmurph50ab051b32016-11-29 22:13:30210
[email protected]907a8bc52013-06-07 16:32:34211 private:
Evan Stadecbb1e002024-09-13 20:06:57212 FRIEND_TEST_ALL_PREFIXES(DatabaseTest, OpenDeleteClear);
Steve Becker4848af32024-10-29 22:57:19213 FRIEND_TEST_ALL_PREFIXES(DatabaseOperationTest,
214 ObjectStoreGetAllKeysWithInvalidObjectStoreId);
215 FRIEND_TEST_ALL_PREFIXES(DatabaseOperationTest,
216 IndexGetAllKeysWithInvalidIndexId);
217 friend class DatabaseOperationTest;
dmurph497e676f12017-04-25 20:29:57218
219 void CallUpgradeTransactionStartedForTesting(int64_t old_version);
220
jsbellef26d19b2016-07-29 22:03:20221 class ConnectionRequest;
jsbell19644202016-07-15 22:27:08222 class OpenRequest;
223 class DeleteRequest;
jsbell0a918e692014-08-23 21:35:56224
Mike Wasserman0d5da522024-09-27 07:47:03225 Status OpenInternal();
[email protected]907a8bc52013-06-07 16:32:34226
Evan Stade4202b1f2024-06-12 16:10:54227 // This class informs its result sink of an error if a `GetAllOperation` is
228 // deleted without being run. This functionality mimics that of
229 // AbortOnDestruct callbacks. `GetAll()` cannot easily be shoe-horned into the
230 // abort-on-destruct callback templating.
Steve Becker4848af32024-10-29 22:57:19231 class CONTENT_EXPORT GetAllResultSinkWrapper {
Evan Stade4202b1f2024-06-12 16:10:54232 public:
Evan Stadecbb1e002024-09-13 20:06:57233 GetAllResultSinkWrapper(base::WeakPtr<Transaction> transaction,
Evan Stade4202b1f2024-06-12 16:10:54234 blink::mojom::IDBDatabase::GetAllCallback callback);
235 ~GetAllResultSinkWrapper();
236
237 mojo::AssociatedRemote<blink::mojom::IDBDatabaseGetAllResultSink>& Get();
238
Steve Becker4848af32024-10-29 22:57:19239 // An override for unit tests to bind the associated receiver successfully
240 // without a pre-existing endpoint entanglement.
241 void UseDedicatedReceiverForTesting() {
242 use_dedicated_receiver_for_testing_ = true;
243 }
244
Evan Stade4202b1f2024-06-12 16:10:54245 private:
Evan Stadecbb1e002024-09-13 20:06:57246 base::WeakPtr<Transaction> transaction_;
Evan Stade4202b1f2024-06-12 16:10:54247 blink::mojom::IDBDatabase::GetAllCallback callback_;
248 mojo::AssociatedRemote<blink::mojom::IDBDatabaseGetAllResultSink>
249 result_sink_;
Steve Becker4848af32024-10-29 22:57:19250 bool use_dedicated_receiver_for_testing_ = false;
Evan Stade4202b1f2024-06-12 16:10:54251 };
252
Mike Wasserman0d5da522024-09-27 07:47:03253 Status GetAllOperation(int64_t object_store_id,
254 int64_t index_id,
Evan Stadeca999b12025-05-09 19:09:11255 blink::IndexedDBKeyRange key_range,
Steve Becker4848af32024-10-29 22:57:19256 blink::mojom::IDBGetAllResultType result_type,
Mike Wasserman0d5da522024-09-27 07:47:03257 int64_t max_count,
Steve Becker4848af32024-10-29 22:57:19258 blink::mojom::IDBCursorDirection direction,
Mike Wasserman0d5da522024-09-27 07:47:03259 std::unique_ptr<GetAllResultSinkWrapper> result_sink,
260 Transaction* transaction);
Evan Stade4202b1f2024-06-12 16:10:54261
Daniel Murphy4c0f9c12019-05-23 01:14:35262 // If there is no active request, grab a new one from the pending queue and
263 // start it. Afterwards, possibly release the database by calling
264 // MaybeReleaseDatabase().
265 void ProcessRequestQueueAndMaybeRelease();
266
267 // If there are no connections, pending requests, or an active request, then
Ari Chivukulafae9b8082022-04-14 22:27:29268 // this function will call `destroy_me_`, which can destruct this object.
Daniel Murphy4c0f9c12019-05-23 01:14:35269 void MaybeReleaseDatabase();
[email protected]907a8bc52013-06-07 16:32:34270
Evan Stadecbb1e002024-09-13 20:06:57271 std::unique_ptr<Connection> CreateConnection(
272 std::unique_ptr<DatabaseCallbacks> database_callbacks,
Evan Stade9f5e401c2024-01-04 23:58:35273 mojo::Remote<storage::mojom::IndexedDBClientStateChecker>
Evan Stade2db7aa72024-02-01 17:07:27274 client_state_checker,
Evan Stade8e75d402024-09-04 00:42:43275 base::UnguessableToken client_token,
276 int scheduling_priority);
[email protected]d29650c2014-03-18 01:20:59277
Daniel Murphy4c0f9c12019-05-23 01:14:35278 // Ack that one of the connections notified with a "versionchange" event did
279 // not promptly close. Therefore a "blocked" event should be fired at the
280 // pending connection.
281 void VersionChangeIgnored();
282
Daniel Murphy7bc96c22019-05-28 22:47:21283 bool HasNoConnections() const;
284
285 void SendVersionChangeToAllConnections(int64_t old_version,
286 int64_t new_version);
287
Daniel Murphy4c0f9c12019-05-23 01:14:35288 // This can only be called when the given connection is closed and no longer
289 // has any transaction objects.
Evan Stadecbb1e002024-09-13 20:06:57290 void ConnectionClosed(Connection* connection);
Daniel Murphy4c0f9c12019-05-23 01:14:35291
Evan Stade8c6ddfd2025-01-06 17:41:10292 // In rare cases there are a very large number of queued
293 // requests/transactions, so calculations related to blocking or blocked
294 // clients can be expensive. See crbug.com/384476946. This method is used for
295 // shortcutting such operations when there's only a single client. Also
296 // returns true for zero clients.
297 bool OnlyHasOneClient() const;
298
Mingyu Lei5cff96b2023-01-13 17:09:51299 // Find the transactions that block `current_transaction` from acquiring the
300 // locks, and ensure that the clients with blocking transactions are active.
301 void RequireBlockingTransactionClientsToBeActive(
Evan Stadecbb1e002024-09-13 20:06:57302 Transaction* current_transaction,
Mingyu Lei5cff96b2023-01-13 17:09:51303 std::vector<PartitionedLockManager::PartitionedLockRequest>&
304 lock_requests);
305
Evan Stadecaa7d182025-04-30 17:42:12306 // Gets metadata for the given object store ID, asserting that the object
307 // store exists.
308 const blink::IndexedDBObjectStoreMetadata& GetObjectStoreMetadata(
309 int64_t object_store_id) const;
310
Evan Stadee24c0072025-06-18 18:29:17311 // This ID uniquely identifies this database within this process. It's not
Abhishek Shanthkumar88ce4902025-06-26 16:00:00312 // persisted anywhere. Only used when the backing store is SQLite.
Evan Stadee24c0072025-06-18 18:29:17313 uint32_t id_for_locks_;
Evan Stade2fbd4532025-04-30 10:19:22314 std::u16string name_;
Evan Stadea35e2722023-09-05 22:53:42315
316 // The object that owns `this`.
Evan Stadecbb1e002024-09-13 20:06:57317 raw_ref<BucketContext> bucket_context_;
Evan Stadea35e2722023-09-05 22:53:42318
Evan Stadecbb1e002024-09-13 20:06:57319 list_set<Connection*> connections_;
Daniel Murphy4c0f9c12019-05-23 01:14:35320
Evan Stade6b4d5a62025-05-29 20:53:53321 // True once `ForceCloseAndRunTasks()` is called.
Daniel Murphy7c750432019-08-20 01:39:47322 bool force_closing_ = false;
Daniel Murphy4c0f9c12019-05-23 01:14:35323
Evan Stadecbb1e002024-09-13 20:06:57324 ConnectionCoordinator connection_coordinator_;
jsbell19644202016-07-15 22:27:08325
Evan Stadee2a68162025-07-08 17:22:54326 // Null until `OpenInternal()` is called successfully, as well as after the
327 // database has been deleted via `DeleteDatabase()`.
Evan Stade2fbd4532025-04-30 10:19:22328 std::unique_ptr<BackingStore::Database> backing_store_db_;
329
Ari Chivukulafae9b8082022-04-14 22:27:29330 // `weak_factory_` is used for all callback uses.
Evan Stadecbb1e002024-09-13 20:06:57331 base::WeakPtrFactory<Database> weak_factory_{this};
[email protected]72a4183d2013-05-31 18:33:10332};
333
Evan Stadecbb1e002024-09-13 20:06:57334} // namespace content::indexed_db
[email protected]72a4183d2013-05-31 18:33:10335
Evan Stade1a8d9d42024-09-10 19:37:19336#endif // CONTENT_BROWSER_INDEXED_DB_INSTANCE_DATABASE_H_