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