1 // Copyright (c) 2013 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 CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_DATABASE_H_ 6 #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_DATABASE_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <list> 12 #include <map> 13 #include <memory> 14 #include <string> 15 #include <tuple> 16 #include <utility> 17 #include <vector> 18 19 #include "base/callback.h" 20 #include "base/containers/queue.h" 21 #include "base/gtest_prod_util.h" 22 #include "base/macros.h" 23 #include "base/memory/ref_counted.h" 24 #include "base/memory/weak_ptr.h" 25 #include "base/strings/string16.h" 26 #include "components/services/storage/indexed_db/scopes/scopes_lock_manager.h" 27 #include "content/browser/indexed_db/indexed_db.h" 28 #include "content/browser/indexed_db/indexed_db_backing_store.h" 29 #include "content/browser/indexed_db/indexed_db_callbacks.h" 30 #include "content/browser/indexed_db/indexed_db_connection_coordinator.h" 31 #include "content/browser/indexed_db/indexed_db_observer.h" 32 #include "content/browser/indexed_db/indexed_db_origin_state_handle.h" 33 #include "content/browser/indexed_db/indexed_db_pending_connection.h" 34 #include "content/browser/indexed_db/indexed_db_task_helper.h" 35 #include "content/browser/indexed_db/indexed_db_value.h" 36 #include "content/browser/indexed_db/list_set.h" 37 #include "content/common/content_export.h" 38 #include "third_party/blink/public/common/indexeddb/indexeddb_key.h" 39 #include "third_party/blink/public/common/indexeddb/web_idb_types.h" 40 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-forward.h" 41 42 namespace blink { 43 class IndexedDBKeyPath; 44 class IndexedDBKeyRange; 45 struct IndexedDBDatabaseMetadata; 46 struct IndexedDBIndexMetadata; 47 struct IndexedDBObjectStoreMetadata; 48 } // namespace blink 49 50 namespace url { 51 class Origin; 52 } 53 54 namespace content { 55 class IndexedDBClassFactory; 56 class IndexedDBConnection; 57 class IndexedDBDatabaseCallbacks; 58 class IndexedDBFactory; 59 class IndexedDBMetadataCoding; 60 class IndexedDBOriginStateHandle; 61 class IndexedDBTransaction; 62 struct IndexedDBValue; 63 64 class CONTENT_EXPORT IndexedDBDatabase { 65 public: 66 // Identifier is pair of (origin, database name). 67 using Identifier = std::pair<url::Origin, base::string16>; 68 // Used to report irrecoverable backend errors. The second argument can be 69 // null. 70 using ErrorCallback = 71 base::RepeatingCallback<void(leveldb::Status, const char*)>; 72 73 static const int64_t kInvalidId = 0; 74 static const int64_t kMinimumIndexId = 30; 75 76 virtual ~IndexedDBDatabase(); 77 identifier()78 const Identifier& identifier() const { return identifier_; } backing_store()79 IndexedDBBackingStore* backing_store() { return backing_store_; } 80 id()81 int64_t id() const { return metadata_.id; } name()82 const base::string16& name() const { return metadata_.name; } origin()83 const url::Origin& origin() const { return identifier_.first; } metadata()84 const blink::IndexedDBDatabaseMetadata& metadata() const { return metadata_; } 85 transaction_lock_manager()86 ScopesLockManager* transaction_lock_manager() { return lock_manager_; } transaction_lock_manager()87 const ScopesLockManager* transaction_lock_manager() const { 88 return lock_manager_; 89 } 90 connections()91 const list_set<IndexedDBConnection*>& connections() const { 92 return connections_; 93 } tasks_available_callback()94 TasksAvailableCallback tasks_available_callback() { 95 return tasks_available_callback_; 96 } 97 98 // TODO(dmurph): Remove this method and have transactions be directly 99 // scheduled using the lock manager. 100 101 enum class RunTasksResult { kDone, kError, kCanBeDestroyed }; 102 std::tuple<RunTasksResult, leveldb::Status> RunTasks(); 103 void RegisterAndScheduleTransaction(IndexedDBTransaction* transaction); 104 105 // The database object (this object) must be kept alive for the duration of 106 // this call. This means the caller should own an IndexedDBOriginStateHandle 107 // while caling this methods. 108 leveldb::Status ForceCloseAndRunTasks(); 109 110 void Commit(IndexedDBTransaction* transaction); 111 112 void TransactionCreated(); 113 void TransactionFinished(blink::mojom::IDBTransactionMode mode, 114 bool committed); 115 116 void AddPendingObserver(IndexedDBTransaction* transaction, 117 int32_t observer_id, 118 const IndexedDBObserver::Options& options); 119 120 // |value| can be null for delete and clear operations. 121 void FilterObservation(IndexedDBTransaction*, 122 int64_t object_store_id, 123 blink::mojom::IDBOperationType type, 124 const blink::IndexedDBKeyRange& key_range, 125 const IndexedDBValue* value); 126 void SendObservations( 127 std::map<int32_t, blink::mojom::IDBObserverChangesPtr> change_map); 128 129 void ScheduleOpenConnection( 130 IndexedDBOriginStateHandle origin_state_handle, 131 std::unique_ptr<IndexedDBPendingConnection> connection); 132 void ScheduleDeleteDatabase(IndexedDBOriginStateHandle origin_state_handle, 133 scoped_refptr<IndexedDBCallbacks> callbacks, 134 base::OnceClosure on_deletion_complete); 135 136 void AddObjectStoreToMetadata(blink::IndexedDBObjectStoreMetadata metadata, 137 int64_t new_max_object_store_id); 138 blink::IndexedDBObjectStoreMetadata RemoveObjectStoreFromMetadata( 139 int64_t object_store_id); 140 void AddIndexToMetadata(int64_t object_store_id, 141 blink::IndexedDBIndexMetadata metadata, 142 int64_t new_max_index_id); 143 blink::IndexedDBIndexMetadata RemoveIndexFromMetadata(int64_t object_store_id, 144 int64_t index_id); 145 146 // The following methods all schedule a task on the transaction & modify the 147 // database: 148 149 // Number of connections that have progressed passed initial open call. ConnectionCount()150 size_t ConnectionCount() const { return connections_.size(); } 151 152 // Number of active open/delete calls (running or blocked on other 153 // connections). ActiveOpenDeleteCount()154 size_t ActiveOpenDeleteCount() const { 155 return connection_coordinator_.ActiveOpenDeleteCount(); 156 } 157 158 // Number of open/delete calls that are waiting their turn. PendingOpenDeleteCount()159 size_t PendingOpenDeleteCount() const { 160 return connection_coordinator_.PendingOpenDeleteCount(); 161 } 162 163 // The following methods are all of the ones actually scheduled asynchronously 164 // within transctions: 165 166 leveldb::Status CreateObjectStoreOperation( 167 int64_t object_store_id, 168 const base::string16& name, 169 const blink::IndexedDBKeyPath& key_path, 170 bool auto_increment, 171 IndexedDBTransaction* transaction); 172 void CreateObjectStoreAbortOperation(int64_t object_store_id); 173 174 leveldb::Status DeleteObjectStoreOperation(int64_t object_store_id, 175 IndexedDBTransaction* transaction); 176 void DeleteObjectStoreAbortOperation( 177 blink::IndexedDBObjectStoreMetadata object_store_metadata); 178 179 leveldb::Status RenameObjectStoreOperation(int64_t object_store_id, 180 const base::string16& new_name, 181 IndexedDBTransaction* transaction); 182 void RenameObjectStoreAbortOperation(int64_t object_store_id, 183 base::string16 old_name); 184 185 leveldb::Status VersionChangeOperation( 186 int64_t version, 187 scoped_refptr<IndexedDBCallbacks> callbacks, 188 IndexedDBTransaction* transaction); 189 void VersionChangeAbortOperation(int64_t previous_version); 190 191 leveldb::Status CreateIndexOperation(int64_t object_store_id, 192 int64_t index_id, 193 const base::string16& name, 194 const blink::IndexedDBKeyPath& key_path, 195 bool unique, 196 bool multi_entry, 197 IndexedDBTransaction* transaction); 198 void CreateIndexAbortOperation(int64_t object_store_id, int64_t index_id); 199 200 leveldb::Status DeleteIndexOperation(int64_t object_store_id, 201 int64_t index_id, 202 IndexedDBTransaction* transaction); 203 void DeleteIndexAbortOperation(int64_t object_store_id, 204 blink::IndexedDBIndexMetadata index_metadata); 205 206 leveldb::Status RenameIndexOperation(int64_t object_store_id, 207 int64_t index_id, 208 const base::string16& new_name, 209 IndexedDBTransaction* transaction); 210 void RenameIndexAbortOperation(int64_t object_store_id, 211 int64_t index_id, 212 base::string16 old_name); 213 214 leveldb::Status GetOperation( 215 base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host, 216 int64_t object_store_id, 217 int64_t index_id, 218 std::unique_ptr<blink::IndexedDBKeyRange> key_range, 219 indexed_db::CursorType cursor_type, 220 blink::mojom::IDBDatabase::GetCallback callback, 221 IndexedDBTransaction* transaction); 222 223 leveldb::Status GetAllOperation( 224 base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host, 225 int64_t object_store_id, 226 int64_t index_id, 227 std::unique_ptr<blink::IndexedDBKeyRange> key_range, 228 indexed_db::CursorType cursor_type, 229 int64_t max_count, 230 blink::mojom::IDBDatabase::GetAllCallback callback, 231 IndexedDBTransaction* transaction); 232 233 struct CONTENT_EXPORT PutOperationParams { 234 PutOperationParams(); 235 ~PutOperationParams(); 236 int64_t object_store_id; 237 IndexedDBValue value; 238 std::unique_ptr<blink::IndexedDBKey> key; 239 blink::mojom::IDBPutMode put_mode; 240 blink::mojom::IDBTransaction::PutCallback callback; 241 std::vector<blink::IndexedDBIndexKeys> index_keys; 242 243 private: 244 DISALLOW_COPY_AND_ASSIGN(PutOperationParams); 245 }; 246 leveldb::Status PutOperation(std::unique_ptr<PutOperationParams> params, 247 IndexedDBTransaction* transaction); 248 249 struct CONTENT_EXPORT PutAllOperationParams { 250 PutAllOperationParams(); 251 ~PutAllOperationParams(); 252 IndexedDBValue value; 253 std::unique_ptr<blink::IndexedDBKey> key; 254 std::vector<blink::IndexedDBIndexKeys> index_keys; 255 256 private: 257 DISALLOW_COPY_AND_ASSIGN(PutAllOperationParams); 258 }; 259 leveldb::Status PutAllOperation( 260 int64_t object_store_id, 261 std::vector<std::unique_ptr<PutAllOperationParams>> params, 262 blink::mojom::IDBTransaction::PutAllCallback callback, 263 IndexedDBTransaction* transaction); 264 265 leveldb::Status SetIndexKeysOperation( 266 int64_t object_store_id, 267 std::unique_ptr<blink::IndexedDBKey> primary_key, 268 const std::vector<blink::IndexedDBIndexKeys>& index_keys, 269 IndexedDBTransaction* transaction); 270 271 leveldb::Status SetIndexesReadyOperation(size_t index_count, 272 IndexedDBTransaction* transaction); 273 274 struct OpenCursorOperationParams { 275 OpenCursorOperationParams(); 276 ~OpenCursorOperationParams(); 277 int64_t object_store_id; 278 int64_t index_id; 279 std::unique_ptr<blink::IndexedDBKeyRange> key_range; 280 blink::mojom::IDBCursorDirection direction; 281 indexed_db::CursorType cursor_type; 282 blink::mojom::IDBTaskType task_type; 283 blink::mojom::IDBDatabase::OpenCursorCallback callback; 284 285 private: 286 DISALLOW_COPY_AND_ASSIGN(OpenCursorOperationParams); 287 }; 288 leveldb::Status OpenCursorOperation( 289 std::unique_ptr<OpenCursorOperationParams> params, 290 const url::Origin& origin, 291 base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host, 292 IndexedDBTransaction* transaction); 293 294 leveldb::Status CountOperation( 295 int64_t object_store_id, 296 int64_t index_id, 297 std::unique_ptr<blink::IndexedDBKeyRange> key_range, 298 scoped_refptr<IndexedDBCallbacks> callbacks, 299 IndexedDBTransaction* transaction); 300 301 leveldb::Status DeleteRangeOperation( 302 int64_t object_store_id, 303 std::unique_ptr<blink::IndexedDBKeyRange> key_range, 304 scoped_refptr<IndexedDBCallbacks> callbacks, 305 IndexedDBTransaction* transaction); 306 307 leveldb::Status GetKeyGeneratorCurrentNumberOperation( 308 int64_t object_store_id, 309 scoped_refptr<IndexedDBCallbacks> callbacks, 310 IndexedDBTransaction* transaction); 311 312 leveldb::Status ClearOperation(int64_t object_store_id, 313 scoped_refptr<IndexedDBCallbacks> callbacks, 314 IndexedDBTransaction* transaction); 315 316 bool IsObjectStoreIdInMetadata(int64_t object_store_id) const; 317 bool IsObjectStoreIdAndIndexIdInMetadata(int64_t object_store_id, 318 int64_t index_id) const; 319 bool IsObjectStoreIdAndMaybeIndexIdInMetadata(int64_t object_store_id, 320 int64_t index_id) const; 321 bool IsObjectStoreIdInMetadataAndIndexNotInMetadata(int64_t object_store_id, 322 int64_t index_id) const; 323 AsWeakPtr()324 base::WeakPtr<IndexedDBDatabase> AsWeakPtr() { 325 return weak_factory_.GetWeakPtr(); 326 } 327 AddConnectionForTesting(IndexedDBConnection * connection)328 void AddConnectionForTesting(IndexedDBConnection* connection) { 329 connections_.insert(connection); 330 } 331 332 protected: 333 friend class IndexedDBTransaction; 334 friend class IndexedDBConnectionCoordinator; 335 friend class IndexedDBConnectionCoordinator::ConnectionRequest; 336 friend class IndexedDBConnectionCoordinator::OpenRequest; 337 friend class IndexedDBConnectionCoordinator::DeleteRequest; 338 339 IndexedDBDatabase(const base::string16& name, 340 IndexedDBBackingStore* backing_store, 341 IndexedDBFactory* factory, 342 IndexedDBClassFactory* class_factory, 343 TasksAvailableCallback tasks_available_callback, 344 std::unique_ptr<IndexedDBMetadataCoding> metadata_coding, 345 const Identifier& unique_identifier, 346 ScopesLockManager* transaction_lock_manager); 347 348 // May be overridden in tests. 349 virtual size_t GetUsableMessageSizeInBytes() const; 350 351 private: 352 friend class MockBrowserTestIndexedDBClassFactory; 353 friend class IndexedDBClassFactory; 354 355 FRIEND_TEST_ALL_PREFIXES(IndexedDBDatabaseTest, OpenDeleteClear); 356 357 void CallUpgradeTransactionStartedForTesting(int64_t old_version); 358 359 class ConnectionRequest; 360 class OpenRequest; 361 class DeleteRequest; 362 363 leveldb::Status OpenInternal(); 364 365 // If there is no active request, grab a new one from the pending queue and 366 // start it. Afterwards, possibly release the database by calling 367 // MaybeReleaseDatabase(). 368 void ProcessRequestQueueAndMaybeRelease(); 369 370 // If there are no connections, pending requests, or an active request, then 371 // this function will call |destroy_me_|, which can destruct this object. 372 void MaybeReleaseDatabase(); 373 374 std::unique_ptr<IndexedDBConnection> CreateConnection( 375 IndexedDBOriginStateHandle origin_state_handle, 376 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks); 377 378 // Ack that one of the connections notified with a "versionchange" event did 379 // not promptly close. Therefore a "blocked" event should be fired at the 380 // pending connection. 381 void VersionChangeIgnored(); 382 383 bool HasNoConnections() const; 384 385 void SendVersionChangeToAllConnections(int64_t old_version, 386 int64_t new_version); 387 388 // This can only be called when the given connection is closed and no longer 389 // has any transaction objects. 390 void ConnectionClosed(IndexedDBConnection* connection); 391 392 bool CanBeDestroyed(); 393 394 // Safe because the IndexedDBBackingStore is owned by the same object which 395 // owns us, the IndexedDBPerOriginFactory. 396 IndexedDBBackingStore* backing_store_; 397 blink::IndexedDBDatabaseMetadata metadata_; 398 399 const Identifier identifier_; 400 // TODO(dmurph): Remove the need for this to be here (and then remove it). 401 IndexedDBFactory* factory_; 402 IndexedDBClassFactory* const class_factory_; 403 std::unique_ptr<IndexedDBMetadataCoding> metadata_coding_; 404 405 ScopesLockManager* lock_manager_; 406 int64_t transaction_count_ = 0; 407 408 list_set<IndexedDBConnection*> connections_; 409 410 TasksAvailableCallback tasks_available_callback_; 411 412 bool force_closing_ = false; 413 414 IndexedDBConnectionCoordinator connection_coordinator_; 415 416 // |weak_factory_| is used for all callback uses. 417 base::WeakPtrFactory<IndexedDBDatabase> weak_factory_{this}; 418 419 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabase); 420 }; 421 422 } // namespace content 423 424 #endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_DATABASE_H_ 425