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_BACKING_STORE_H_ 6 #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_ 7 8 #include <map> 9 #include <set> 10 #include <string> 11 #include <utility> 12 #include <vector> 13 14 #include "base/basictypes.h" 15 #include "base/files/file_path.h" 16 #include "base/memory/ref_counted.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/strings/string_piece.h" 19 #include "base/time/time.h" 20 #include "base/timer/timer.h" 21 #include "content/browser/indexed_db/indexed_db.h" 22 #include "content/browser/indexed_db/indexed_db_active_blob_registry.h" 23 #include "content/browser/indexed_db/indexed_db_blob_info.h" 24 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" 25 #include "content/browser/indexed_db/indexed_db_metadata.h" 26 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" 27 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" 28 #include "content/common/content_export.h" 29 #include "content/common/indexed_db/indexed_db_key.h" 30 #include "content/common/indexed_db/indexed_db_key_path.h" 31 #include "content/common/indexed_db/indexed_db_key_range.h" 32 #include "storage/browser/blob/blob_data_handle.h" 33 #include "third_party/leveldatabase/src/include/leveldb/status.h" 34 #include "url/gurl.h" 35 36 namespace base { 37 class SequencedTaskRunner; 38 } 39 40 namespace storage { 41 class FileWriterDelegate; 42 } 43 44 namespace net { 45 class URLRequestContext; 46 } 47 48 namespace content { 49 50 class IndexedDBFactory; 51 class LevelDBComparator; 52 class LevelDBDatabase; 53 class LevelDBFactory; 54 struct IndexedDBValue; 55 56 class CONTENT_EXPORT IndexedDBBackingStore 57 : public base::RefCounted<IndexedDBBackingStore> { 58 public: 59 class CONTENT_EXPORT Comparator : public LevelDBComparator { 60 public: 61 virtual int Compare(const base::StringPiece& a, 62 const base::StringPiece& b) const OVERRIDE; 63 virtual const char* Name() const OVERRIDE; 64 }; 65 66 class CONTENT_EXPORT RecordIdentifier { 67 public: 68 RecordIdentifier(const std::string& primary_key, int64 version); 69 RecordIdentifier(); 70 ~RecordIdentifier(); 71 72 const std::string& primary_key() const { return primary_key_; } 73 int64 version() const { return version_; } 74 void Reset(const std::string& primary_key, int64 version) { 75 primary_key_ = primary_key; 76 version_ = version; 77 } 78 79 private: 80 // TODO(jsbell): Make it more clear that this is the *encoded* version of 81 // the key. 82 std::string primary_key_; 83 int64 version_; 84 DISALLOW_COPY_AND_ASSIGN(RecordIdentifier); 85 }; 86 87 class BlobWriteCallback : public base::RefCounted<BlobWriteCallback> { 88 public: 89 virtual void Run(bool succeeded) = 0; 90 91 protected: 92 friend class base::RefCounted<BlobWriteCallback>; 93 virtual ~BlobWriteCallback() {} 94 }; 95 96 class BlobChangeRecord { 97 public: 98 BlobChangeRecord(const std::string& key, int64 object_store_id); 99 ~BlobChangeRecord(); 100 101 const std::string& key() const { return key_; } 102 int64 object_store_id() const { return object_store_id_; } 103 void SetBlobInfo(std::vector<IndexedDBBlobInfo>* blob_info); 104 std::vector<IndexedDBBlobInfo>& mutable_blob_info() { return blob_info_; } 105 const std::vector<IndexedDBBlobInfo>& blob_info() const { 106 return blob_info_; 107 } 108 void SetHandles(ScopedVector<storage::BlobDataHandle>* handles); 109 scoped_ptr<BlobChangeRecord> Clone() const; 110 111 private: 112 std::string key_; 113 int64 object_store_id_; 114 std::vector<IndexedDBBlobInfo> blob_info_; 115 ScopedVector<storage::BlobDataHandle> handles_; 116 DISALLOW_COPY_AND_ASSIGN(BlobChangeRecord); 117 }; 118 typedef std::map<std::string, BlobChangeRecord*> BlobChangeMap; 119 120 class CONTENT_EXPORT Transaction { 121 public: 122 explicit Transaction(IndexedDBBackingStore* backing_store); 123 virtual ~Transaction(); 124 125 virtual void Begin(); 126 // The callback will be called eventually on success or failure, or 127 // immediately if phase one is complete due to lack of any blobs to write. 128 virtual leveldb::Status CommitPhaseOne(scoped_refptr<BlobWriteCallback>); 129 virtual leveldb::Status CommitPhaseTwo(); 130 virtual void Rollback(); 131 void Reset() { 132 backing_store_ = NULL; 133 transaction_ = NULL; 134 } 135 leveldb::Status PutBlobInfoIfNeeded( 136 int64 database_id, 137 int64 object_store_id, 138 const std::string& object_store_data_key, 139 std::vector<IndexedDBBlobInfo>*, 140 ScopedVector<storage::BlobDataHandle>* handles); 141 void PutBlobInfo(int64 database_id, 142 int64 object_store_id, 143 const std::string& object_store_data_key, 144 std::vector<IndexedDBBlobInfo>*, 145 ScopedVector<storage::BlobDataHandle>* handles); 146 147 LevelDBTransaction* transaction() { return transaction_.get(); } 148 149 leveldb::Status GetBlobInfoForRecord( 150 int64 database_id, 151 const std::string& object_store_data_key, 152 IndexedDBValue* value); 153 154 // This holds a BlobEntryKey and the encoded IndexedDBBlobInfo vector stored 155 // under that key. 156 typedef std::vector<std::pair<BlobEntryKey, std::string> > 157 BlobEntryKeyValuePairVec; 158 159 class WriteDescriptor { 160 public: 161 WriteDescriptor(const GURL& url, int64_t key, int64_t size); 162 WriteDescriptor(const base::FilePath& path, 163 int64_t key, 164 int64_t size, 165 base::Time last_modified); 166 167 bool is_file() const { return is_file_; } 168 const GURL& url() const { 169 DCHECK(!is_file_); 170 return url_; 171 } 172 const base::FilePath& file_path() const { 173 DCHECK(is_file_); 174 return file_path_; 175 } 176 int64_t key() const { return key_; } 177 int64_t size() const { return size_; } 178 base::Time last_modified() const { return last_modified_; } 179 180 private: 181 bool is_file_; 182 GURL url_; 183 base::FilePath file_path_; 184 int64_t key_; 185 int64_t size_; 186 base::Time last_modified_; 187 }; 188 189 class ChainedBlobWriter 190 : public base::RefCountedThreadSafe<ChainedBlobWriter> { 191 public: 192 virtual void set_delegate( 193 scoped_ptr<storage::FileWriterDelegate> delegate) = 0; 194 195 // TODO(ericu): Add a reason in the event of failure. 196 virtual void ReportWriteCompletion(bool succeeded, 197 int64 bytes_written) = 0; 198 199 virtual void Abort() = 0; 200 201 protected: 202 friend class base::RefCountedThreadSafe<ChainedBlobWriter>; 203 virtual ~ChainedBlobWriter() {} 204 }; 205 206 class ChainedBlobWriterImpl; 207 208 typedef std::vector<WriteDescriptor> WriteDescriptorVec; 209 210 private: 211 class BlobWriteCallbackWrapper; 212 213 leveldb::Status HandleBlobPreTransaction( 214 BlobEntryKeyValuePairVec* new_blob_entries, 215 WriteDescriptorVec* new_files_to_write); 216 // Returns true on success, false on failure. 217 bool CollectBlobFilesToRemove(); 218 // The callback will be called eventually on success or failure. 219 void WriteNewBlobs(BlobEntryKeyValuePairVec* new_blob_entries, 220 WriteDescriptorVec* new_files_to_write, 221 scoped_refptr<BlobWriteCallback> callback); 222 leveldb::Status SortBlobsToRemove(); 223 224 IndexedDBBackingStore* backing_store_; 225 scoped_refptr<LevelDBTransaction> transaction_; 226 BlobChangeMap blob_change_map_; 227 BlobChangeMap incognito_blob_map_; 228 int64 database_id_; 229 BlobJournalType blobs_to_remove_; 230 scoped_refptr<ChainedBlobWriter> chained_blob_writer_; 231 }; 232 233 class Cursor { 234 public: 235 enum IteratorState { READY = 0, SEEK }; 236 237 virtual ~Cursor(); 238 239 struct CursorOptions { 240 CursorOptions(); 241 ~CursorOptions(); 242 int64 database_id; 243 int64 object_store_id; 244 int64 index_id; 245 std::string low_key; 246 bool low_open; 247 std::string high_key; 248 bool high_open; 249 bool forward; 250 bool unique; 251 }; 252 253 const IndexedDBKey& key() const { return *current_key_; } 254 bool Continue(leveldb::Status* s) { return Continue(NULL, NULL, SEEK, s); } 255 bool Continue(const IndexedDBKey* key, 256 IteratorState state, 257 leveldb::Status* s) { 258 return Continue(key, NULL, state, s); 259 } 260 bool Continue(const IndexedDBKey* key, 261 const IndexedDBKey* primary_key, 262 IteratorState state, 263 leveldb::Status*); 264 bool Advance(uint32 count, leveldb::Status*); 265 bool FirstSeek(leveldb::Status*); 266 267 virtual Cursor* Clone() = 0; 268 virtual const IndexedDBKey& primary_key() const; 269 virtual IndexedDBValue* value() = 0; 270 virtual const RecordIdentifier& record_identifier() const; 271 virtual bool LoadCurrentRow() = 0; 272 273 protected: 274 Cursor(scoped_refptr<IndexedDBBackingStore> backing_store, 275 Transaction* transaction, 276 int64 database_id, 277 const CursorOptions& cursor_options); 278 explicit Cursor(const IndexedDBBackingStore::Cursor* other); 279 280 virtual std::string EncodeKey(const IndexedDBKey& key) = 0; 281 virtual std::string EncodeKey(const IndexedDBKey& key, 282 const IndexedDBKey& primary_key) = 0; 283 284 bool IsPastBounds() const; 285 bool HaveEnteredRange() const; 286 287 IndexedDBBackingStore* backing_store_; 288 Transaction* transaction_; 289 int64 database_id_; 290 const CursorOptions cursor_options_; 291 scoped_ptr<LevelDBIterator> iterator_; 292 scoped_ptr<IndexedDBKey> current_key_; 293 IndexedDBBackingStore::RecordIdentifier record_identifier_; 294 295 private: 296 DISALLOW_COPY_AND_ASSIGN(Cursor); 297 }; 298 299 const GURL& origin_url() const { return origin_url_; } 300 IndexedDBFactory* factory() const { return indexed_db_factory_; } 301 base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); } 302 base::OneShotTimer<IndexedDBBackingStore>* close_timer() { 303 return &close_timer_; 304 } 305 IndexedDBActiveBlobRegistry* active_blob_registry() { 306 return &active_blob_registry_; 307 } 308 309 static scoped_refptr<IndexedDBBackingStore> Open( 310 IndexedDBFactory* indexed_db_factory, 311 const GURL& origin_url, 312 const base::FilePath& path_base, 313 net::URLRequestContext* request_context, 314 blink::WebIDBDataLoss* data_loss, 315 std::string* data_loss_message, 316 bool* disk_full, 317 base::SequencedTaskRunner* task_runner, 318 bool clean_journal, 319 leveldb::Status* status); 320 static scoped_refptr<IndexedDBBackingStore> Open( 321 IndexedDBFactory* indexed_db_factory, 322 const GURL& origin_url, 323 const base::FilePath& path_base, 324 net::URLRequestContext* request_context, 325 blink::WebIDBDataLoss* data_loss, 326 std::string* data_loss_message, 327 bool* disk_full, 328 LevelDBFactory* leveldb_factory, 329 base::SequencedTaskRunner* task_runner, 330 bool clean_journal, 331 leveldb::Status* status); 332 static scoped_refptr<IndexedDBBackingStore> OpenInMemory( 333 const GURL& origin_url, 334 base::SequencedTaskRunner* task_runner, 335 leveldb::Status* status); 336 static scoped_refptr<IndexedDBBackingStore> OpenInMemory( 337 const GURL& origin_url, 338 LevelDBFactory* leveldb_factory, 339 base::SequencedTaskRunner* task_runner, 340 leveldb::Status* status); 341 342 void GrantChildProcessPermissions(int child_process_id); 343 344 // Compact is public for testing. 345 virtual void Compact(); 346 virtual std::vector<base::string16> GetDatabaseNames(leveldb::Status*); 347 virtual leveldb::Status GetIDBDatabaseMetaData( 348 const base::string16& name, 349 IndexedDBDatabaseMetadata* metadata, 350 bool* success) WARN_UNUSED_RESULT; 351 virtual leveldb::Status CreateIDBDatabaseMetaData( 352 const base::string16& name, 353 const base::string16& version, 354 int64 int_version, 355 int64* row_id); 356 virtual bool UpdateIDBDatabaseIntVersion( 357 IndexedDBBackingStore::Transaction* transaction, 358 int64 row_id, 359 int64 int_version); 360 virtual leveldb::Status DeleteDatabase(const base::string16& name); 361 362 // Assumes caller has already closed the backing store. 363 static leveldb::Status DestroyBackingStore(const base::FilePath& path_base, 364 const GURL& origin_url); 365 static bool RecordCorruptionInfo(const base::FilePath& path_base, 366 const GURL& origin_url, 367 const std::string& message); 368 leveldb::Status GetObjectStores( 369 int64 database_id, 370 IndexedDBDatabaseMetadata::ObjectStoreMap* map) WARN_UNUSED_RESULT; 371 virtual leveldb::Status CreateObjectStore( 372 IndexedDBBackingStore::Transaction* transaction, 373 int64 database_id, 374 int64 object_store_id, 375 const base::string16& name, 376 const IndexedDBKeyPath& key_path, 377 bool auto_increment); 378 virtual leveldb::Status DeleteObjectStore( 379 IndexedDBBackingStore::Transaction* transaction, 380 int64 database_id, 381 int64 object_store_id) WARN_UNUSED_RESULT; 382 383 virtual leveldb::Status GetRecord( 384 IndexedDBBackingStore::Transaction* transaction, 385 int64 database_id, 386 int64 object_store_id, 387 const IndexedDBKey& key, 388 IndexedDBValue* record) WARN_UNUSED_RESULT; 389 virtual leveldb::Status PutRecord( 390 IndexedDBBackingStore::Transaction* transaction, 391 int64 database_id, 392 int64 object_store_id, 393 const IndexedDBKey& key, 394 IndexedDBValue* value, 395 ScopedVector<storage::BlobDataHandle>* handles, 396 RecordIdentifier* record) WARN_UNUSED_RESULT; 397 virtual leveldb::Status ClearObjectStore( 398 IndexedDBBackingStore::Transaction* transaction, 399 int64 database_id, 400 int64 object_store_id) WARN_UNUSED_RESULT; 401 virtual leveldb::Status DeleteRecord( 402 IndexedDBBackingStore::Transaction* transaction, 403 int64 database_id, 404 int64 object_store_id, 405 const RecordIdentifier& record) WARN_UNUSED_RESULT; 406 virtual leveldb::Status DeleteRange( 407 IndexedDBBackingStore::Transaction* transaction, 408 int64 database_id, 409 int64 object_store_id, 410 const IndexedDBKeyRange&) WARN_UNUSED_RESULT; 411 virtual leveldb::Status GetKeyGeneratorCurrentNumber( 412 IndexedDBBackingStore::Transaction* transaction, 413 int64 database_id, 414 int64 object_store_id, 415 int64* current_number) WARN_UNUSED_RESULT; 416 virtual leveldb::Status MaybeUpdateKeyGeneratorCurrentNumber( 417 IndexedDBBackingStore::Transaction* transaction, 418 int64 database_id, 419 int64 object_store_id, 420 int64 new_state, 421 bool check_current) WARN_UNUSED_RESULT; 422 virtual leveldb::Status KeyExistsInObjectStore( 423 IndexedDBBackingStore::Transaction* transaction, 424 int64 database_id, 425 int64 object_store_id, 426 const IndexedDBKey& key, 427 RecordIdentifier* found_record_identifier, 428 bool* found) WARN_UNUSED_RESULT; 429 430 virtual leveldb::Status CreateIndex( 431 IndexedDBBackingStore::Transaction* transaction, 432 int64 database_id, 433 int64 object_store_id, 434 int64 index_id, 435 const base::string16& name, 436 const IndexedDBKeyPath& key_path, 437 bool is_unique, 438 bool is_multi_entry) WARN_UNUSED_RESULT; 439 virtual leveldb::Status DeleteIndex( 440 IndexedDBBackingStore::Transaction* transaction, 441 int64 database_id, 442 int64 object_store_id, 443 int64 index_id) WARN_UNUSED_RESULT; 444 virtual leveldb::Status PutIndexDataForRecord( 445 IndexedDBBackingStore::Transaction* transaction, 446 int64 database_id, 447 int64 object_store_id, 448 int64 index_id, 449 const IndexedDBKey& key, 450 const RecordIdentifier& record) WARN_UNUSED_RESULT; 451 virtual leveldb::Status GetPrimaryKeyViaIndex( 452 IndexedDBBackingStore::Transaction* transaction, 453 int64 database_id, 454 int64 object_store_id, 455 int64 index_id, 456 const IndexedDBKey& key, 457 scoped_ptr<IndexedDBKey>* primary_key) WARN_UNUSED_RESULT; 458 virtual leveldb::Status KeyExistsInIndex( 459 IndexedDBBackingStore::Transaction* transaction, 460 int64 database_id, 461 int64 object_store_id, 462 int64 index_id, 463 const IndexedDBKey& key, 464 scoped_ptr<IndexedDBKey>* found_primary_key, 465 bool* exists) WARN_UNUSED_RESULT; 466 467 // Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef. 468 virtual void ReportBlobUnused(int64 database_id, int64 blob_key); 469 470 base::FilePath GetBlobFileName(int64 database_id, int64 key); 471 472 virtual scoped_ptr<Cursor> OpenObjectStoreKeyCursor( 473 IndexedDBBackingStore::Transaction* transaction, 474 int64 database_id, 475 int64 object_store_id, 476 const IndexedDBKeyRange& key_range, 477 blink::WebIDBCursorDirection, 478 leveldb::Status*); 479 virtual scoped_ptr<Cursor> OpenObjectStoreCursor( 480 IndexedDBBackingStore::Transaction* transaction, 481 int64 database_id, 482 int64 object_store_id, 483 const IndexedDBKeyRange& key_range, 484 blink::WebIDBCursorDirection, 485 leveldb::Status*); 486 virtual scoped_ptr<Cursor> OpenIndexKeyCursor( 487 IndexedDBBackingStore::Transaction* transaction, 488 int64 database_id, 489 int64 object_store_id, 490 int64 index_id, 491 const IndexedDBKeyRange& key_range, 492 blink::WebIDBCursorDirection, 493 leveldb::Status*); 494 virtual scoped_ptr<Cursor> OpenIndexCursor( 495 IndexedDBBackingStore::Transaction* transaction, 496 int64 database_id, 497 int64 object_store_id, 498 int64 index_id, 499 const IndexedDBKeyRange& key_range, 500 blink::WebIDBCursorDirection, 501 leveldb::Status*); 502 503 protected: 504 friend class base::RefCounted<IndexedDBBackingStore>; 505 506 IndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, 507 const GURL& origin_url, 508 const base::FilePath& blob_path, 509 net::URLRequestContext* request_context, 510 scoped_ptr<LevelDBDatabase> db, 511 scoped_ptr<LevelDBComparator> comparator, 512 base::SequencedTaskRunner* task_runner); 513 virtual ~IndexedDBBackingStore(); 514 515 bool is_incognito() const { return !indexed_db_factory_; } 516 517 leveldb::Status SetUpMetadata(); 518 519 virtual bool WriteBlobFile( 520 int64 database_id, 521 const Transaction::WriteDescriptor& descriptor, 522 Transaction::ChainedBlobWriter* chained_blob_writer); 523 virtual bool RemoveBlobFile(int64 database_id, int64 key); 524 virtual void StartJournalCleaningTimer(); 525 void CleanPrimaryJournalIgnoreReturn(); 526 527 private: 528 static scoped_refptr<IndexedDBBackingStore> Create( 529 IndexedDBFactory* indexed_db_factory, 530 const GURL& origin_url, 531 const base::FilePath& blob_path, 532 net::URLRequestContext* request_context, 533 scoped_ptr<LevelDBDatabase> db, 534 scoped_ptr<LevelDBComparator> comparator, 535 base::SequencedTaskRunner* task_runner, 536 leveldb::Status* status); 537 538 static bool ReadCorruptionInfo(const base::FilePath& path_base, 539 const GURL& origin_url, 540 std::string* message); 541 542 leveldb::Status FindKeyInIndex( 543 IndexedDBBackingStore::Transaction* transaction, 544 int64 database_id, 545 int64 object_store_id, 546 int64 index_id, 547 const IndexedDBKey& key, 548 std::string* found_encoded_primary_key, 549 bool* found); 550 leveldb::Status GetIndexes(int64 database_id, 551 int64 object_store_id, 552 IndexedDBObjectStoreMetadata::IndexMap* map) 553 WARN_UNUSED_RESULT; 554 bool RemoveBlobDirectory(int64 database_id); 555 leveldb::Status CleanUpBlobJournal(const std::string& level_db_key); 556 557 IndexedDBFactory* indexed_db_factory_; 558 const GURL origin_url_; 559 base::FilePath blob_path_; 560 561 // The origin identifier is a key prefix unique to the origin used in the 562 // leveldb backing store to partition data by origin. It is a normalized 563 // version of the origin URL with a versioning suffix appended, e.g. 564 // "http_localhost_81@1" Since only one origin is stored per backing store 565 // this is redundant but necessary for backwards compatibility; the suffix 566 // provides for future flexibility. 567 const std::string origin_identifier_; 568 569 net::URLRequestContext* request_context_; 570 scoped_refptr<base::SequencedTaskRunner> task_runner_; 571 std::set<int> child_process_ids_granted_; 572 BlobChangeMap incognito_blob_map_; 573 base::OneShotTimer<IndexedDBBackingStore> journal_cleaning_timer_; 574 575 scoped_ptr<LevelDBDatabase> db_; 576 scoped_ptr<LevelDBComparator> comparator_; 577 // Whenever blobs are registered in active_blob_registry_, indexed_db_factory_ 578 // will hold a reference to this backing store. 579 IndexedDBActiveBlobRegistry active_blob_registry_; 580 base::OneShotTimer<IndexedDBBackingStore> close_timer_; 581 582 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStore); 583 }; 584 585 } // namespace content 586 587 #endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_ 588