Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" | 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/string_piece.h" | 10 #include "base/strings/string_piece.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "base/strings/stringprintf.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "content/browser/child_process_security_policy_impl.h" | |
| 15 #include "content/browser/indexed_db/indexed_db_blob_info.h" | |
| 13 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 16 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
| 14 #include "content/browser/indexed_db/indexed_db_metadata.h" | 17 #include "content/browser/indexed_db/indexed_db_metadata.h" |
| 15 #include "content/browser/indexed_db/indexed_db_tracing.h" | 18 #include "content/browser/indexed_db/indexed_db_tracing.h" |
| 19 #include "content/browser/indexed_db/indexed_db_value.h" | |
| 16 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" | 20 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" |
| 17 #include "content/browser/indexed_db/leveldb/leveldb_database.h" | 21 #include "content/browser/indexed_db/leveldb/leveldb_database.h" |
| 18 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" | 22 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" |
| 19 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" | 23 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" |
| 20 #include "content/common/indexed_db/indexed_db_key.h" | 24 #include "content/common/indexed_db/indexed_db_key.h" |
| 21 #include "content/common/indexed_db/indexed_db_key_path.h" | 25 #include "content/common/indexed_db/indexed_db_key_path.h" |
| 22 #include "content/common/indexed_db/indexed_db_key_range.h" | 26 #include "content/common/indexed_db/indexed_db_key_range.h" |
| 27 #include "content/public/browser/browser_thread.h" | |
| 28 #include "net/url_request/url_request_context.h" | |
| 23 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 29 #include "third_party/WebKit/public/platform/WebIDBTypes.h" |
| 24 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" | 30 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" |
| 25 #include "third_party/leveldatabase/env_chromium.h" | 31 #include "third_party/leveldatabase/env_chromium.h" |
| 32 #include "webkit/browser/blob/blob_data_handle.h" | |
| 33 #include "webkit/browser/fileapi/file_stream_writer.h" | |
| 34 #include "webkit/browser/fileapi/file_writer_delegate.h" | |
| 35 #include "webkit/browser/fileapi/local_file_stream_writer.h" | |
| 26 #include "webkit/common/database/database_identifier.h" | 36 #include "webkit/common/database/database_identifier.h" |
| 27 | 37 |
| 38 using base::FilePath; | |
| 28 using base::StringPiece; | 39 using base::StringPiece; |
| 40 using fileapi::FileWriterDelegate; | |
| 29 | 41 |
| 30 namespace content { | 42 namespace content { |
| 31 | 43 |
| 32 namespace { | 44 namespace { |
| 33 | 45 |
| 46 FilePath GetIDBBlobDirectoryName(const FilePath& pathBase, | |
|
jsbell
2013/12/18 23:04:40
Suggestion: Drop the 'IDB' in function names here
ericu
2013/12/19 05:19:11
Done.
| |
| 47 int64 database_id) { | |
|
jsbell
2013/12/18 23:04:40
Indentation... although I'm going to assume you'll
ericu
2013/12/19 05:19:11
Just tried git cl format for the first time. Awes
| |
| 48 return pathBase.AppendASCII(base::StringPrintf("%lx", database_id)); | |
| 49 } | |
| 50 | |
| 51 FilePath GetIDBBlobDirectoryNameForKey(const FilePath& pathBase, | |
| 52 int64 database_id, int64 key) { | |
| 53 FilePath path = GetIDBBlobDirectoryName(pathBase, database_id); | |
| 54 path = path.AppendASCII( | |
| 55 base::StringPrintf("%x", static_cast<int>(key & 0x0000ff00) >> 8)); | |
|
jsbell
2013/12/18 23:04:40
Would there be any disadvantage to using %02x so t
ericu
2013/12/19 05:19:11
Well, the first few will be bigger than they need
ericu
2014/02/25 21:19:44
Note that I haven't done this for the filenames or
| |
| 56 return path; | |
| 57 } | |
| 58 | |
| 59 // This assumes a file path of dbId/3rd-byte-of-counter/counter. | |
| 60 bool MakeIDBBlobDirectory( | |
| 61 const FilePath& pathBase, int64 database_id, int64 key) { | |
| 62 FilePath path = | |
| 63 GetIDBBlobDirectoryNameForKey(pathBase, database_id, key); | |
| 64 return file_util::CreateDirectory(path); | |
| 65 } | |
| 66 | |
| 34 static std::string ComputeOriginIdentifier(const GURL& origin_url) { | 67 static std::string ComputeOriginIdentifier(const GURL& origin_url) { |
| 35 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; | 68 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; |
| 36 } | 69 } |
| 37 | 70 |
| 38 static base::FilePath ComputeFileName(const GURL& origin_url) { | 71 static base::FilePath ComputeFileName(const GURL& origin_url) { |
| 39 return base::FilePath() | 72 return base::FilePath() |
| 40 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) | 73 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) |
| 41 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); | 74 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); |
| 42 } | 75 } |
| 43 | 76 |
| 77 static base::FilePath ComputeBlobPath(const GURL& origin_url) { | |
| 78 return base::FilePath() | |
| 79 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) | |
| 80 .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob")); | |
| 81 } | |
| 82 | |
| 44 } // namespace | 83 } // namespace |
| 45 | 84 |
| 46 static const int64 kKeyGeneratorInitialNumber = | 85 static const int64 kKeyGeneratorInitialNumber = |
| 47 1; // From the IndexedDB specification. | 86 1; // From the IndexedDB specification. |
| 48 | 87 |
| 49 enum IndexedDBBackingStoreErrorSource { | 88 enum IndexedDBBackingStoreErrorSource { |
| 50 // 0 - 2 are no longer used. | 89 // 0 - 2 are no longer used. |
| 51 FIND_KEY_IN_INDEX = 3, | 90 FIND_KEY_IN_INDEX = 3, |
| 52 GET_IDBDATABASE_METADATA, | 91 GET_IDBDATABASE_METADATA, |
| 53 GET_INDEXES, | 92 GET_INDEXES, |
| 54 GET_KEY_GENERATOR_CURRENT_NUMBER, | 93 GET_KEY_GENERATOR_CURRENT_NUMBER, |
| 55 GET_OBJECT_STORES, | 94 GET_OBJECT_STORES, |
| 56 GET_RECORD, | 95 GET_RECORD, |
| 57 KEY_EXISTS_IN_OBJECT_STORE, | 96 KEY_EXISTS_IN_OBJECT_STORE, |
| 58 LOAD_CURRENT_ROW, | 97 LOAD_CURRENT_ROW, |
| 59 SET_UP_METADATA, | 98 SET_UP_METADATA, |
| 60 GET_PRIMARY_KEY_VIA_INDEX, | 99 GET_PRIMARY_KEY_VIA_INDEX, |
| 61 KEY_EXISTS_IN_INDEX, | 100 KEY_EXISTS_IN_INDEX, |
| 62 VERSION_EXISTS, | 101 VERSION_EXISTS, |
| 63 DELETE_OBJECT_STORE, | 102 DELETE_OBJECT_STORE, |
| 64 SET_MAX_OBJECT_STORE_ID, | 103 SET_MAX_OBJECT_STORE_ID, |
| 65 SET_MAX_INDEX_ID, | 104 SET_MAX_INDEX_ID, |
| 66 GET_NEW_DATABASE_ID, | 105 GET_NEW_DATABASE_ID, |
| 67 GET_NEW_VERSION_NUMBER, | 106 GET_NEW_VERSION_NUMBER, |
| 68 CREATE_IDBDATABASE_METADATA, | 107 CREATE_IDBDATABASE_METADATA, |
| 69 DELETE_DATABASE, | 108 DELETE_DATABASE, |
| 70 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro | 109 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro |
| 110 GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER, | |
|
jsbell
2013/12/18 23:04:40
Need to append (after GET_DATABASE_NAMES) to retai
ericu
2013/12/19 05:19:11
Done.
| |
| 111 GET_BLOB_INFO_FOR_RECORD, | |
| 112 DECODE_BLOB_JOURNAL, | |
| 71 GET_DATABASE_NAMES, | 113 GET_DATABASE_NAMES, |
| 72 INTERNAL_ERROR_MAX, | 114 INTERNAL_ERROR_MAX, |
| 73 }; | 115 }; |
| 74 | 116 |
| 75 static void RecordInternalError(const char* type, | 117 static void RecordInternalError(const char* type, |
| 76 IndexedDBBackingStoreErrorSource location) { | 118 IndexedDBBackingStoreErrorSource location) { |
| 77 std::string name; | 119 std::string name; |
| 78 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); | 120 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); |
| 79 base::Histogram::FactoryGet(name, | 121 base::Histogram::FactoryGet(name, |
| 80 1, | 122 1, |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 | 277 |
| 236 if (db_data_version > latest_known_data_version) { | 278 if (db_data_version > latest_known_data_version) { |
| 237 *known = false; | 279 *known = false; |
| 238 return true; | 280 return true; |
| 239 } | 281 } |
| 240 | 282 |
| 241 *known = true; | 283 *known = true; |
| 242 return true; | 284 return true; |
| 243 } | 285 } |
| 244 | 286 |
| 245 WARN_UNUSED_RESULT static bool SetUpMetadata( | 287 WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() { |
|
jsbell
2013/12/18 23:04:40
Land separately?
ericu
2013/12/19 05:19:11
Sure; that's just there to help the unit test, so
| |
| 246 LevelDBDatabase* db, | |
| 247 const std::string& origin_identifier) { | |
| 248 const uint32 latest_known_data_version = | 288 const uint32 latest_known_data_version = |
| 249 blink::kSerializedScriptValueVersion; | 289 blink::kSerializedScriptValueVersion; |
| 250 const std::string schema_version_key = SchemaVersionKey::Encode(); | 290 const std::string schema_version_key = SchemaVersionKey::Encode(); |
| 251 const std::string data_version_key = DataVersionKey::Encode(); | 291 const std::string data_version_key = DataVersionKey::Encode(); |
| 252 | 292 |
| 253 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db); | 293 scoped_refptr<LevelDBTransaction> transaction = |
| 294 new LevelDBTransaction(db_.get()); | |
| 254 | 295 |
| 255 int64 db_schema_version = 0; | 296 int64 db_schema_version = 0; |
| 256 int64 db_data_version = 0; | 297 int64 db_data_version = 0; |
| 257 bool found = false; | 298 bool found = false; |
| 258 bool ok = | 299 bool ok = |
| 259 GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); | 300 GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); |
| 260 if (!ok) { | 301 if (!ok) { |
| 261 INTERNAL_READ_ERROR(SET_UP_METADATA); | 302 INTERNAL_READ_ERROR(SET_UP_METADATA); |
| 262 return false; | 303 return false; |
| 263 } | 304 } |
| 264 if (!found) { | 305 if (!found) { |
| 265 // Initialize new backing store. | 306 // Initialize new backing store. |
| 266 db_schema_version = kLatestKnownSchemaVersion; | 307 db_schema_version = kLatestKnownSchemaVersion; |
| 267 PutInt(transaction.get(), schema_version_key, db_schema_version); | 308 PutInt(transaction.get(), schema_version_key, db_schema_version); |
| 268 db_data_version = latest_known_data_version; | 309 db_data_version = latest_known_data_version; |
| 269 PutInt(transaction.get(), data_version_key, db_data_version); | 310 PutInt(transaction.get(), data_version_key, db_data_version); |
| 270 } else { | 311 } else { |
| 271 // Upgrade old backing store. | 312 // Upgrade old backing store. |
| 272 DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion); | 313 DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion); |
| 273 if (db_schema_version < 1) { | 314 if (db_schema_version < 1) { |
| 274 db_schema_version = 1; | 315 db_schema_version = 1; |
| 275 PutInt(transaction.get(), schema_version_key, db_schema_version); | 316 PutInt(transaction.get(), schema_version_key, db_schema_version); |
| 276 const std::string start_key = | 317 const std::string start_key = |
| 277 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier); | 318 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); |
| 278 const std::string stop_key = | 319 const std::string stop_key = |
| 279 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier); | 320 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); |
| 280 scoped_ptr<LevelDBIterator> it = db->CreateIterator(); | 321 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
| 281 for (it->Seek(start_key); | 322 for (it->Seek(start_key); |
| 282 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; | 323 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; |
| 283 it->Next()) { | 324 it->Next()) { |
| 284 int64 database_id = 0; | 325 int64 database_id = 0; |
| 285 found = false; | 326 found = false; |
| 286 bool ok = GetInt(transaction.get(), it->Key(), &database_id, &found); | 327 bool ok = GetInt(transaction.get(), it->Key(), &database_id, &found); |
| 287 if (!ok) { | 328 if (!ok) { |
| 288 INTERNAL_READ_ERROR(SET_UP_METADATA); | 329 INTERNAL_READ_ERROR(SET_UP_METADATA); |
| 289 return false; | 330 return false; |
| 290 } | 331 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 } | 403 } |
| 363 | 404 |
| 364 class DefaultLevelDBFactory : public LevelDBFactory { | 405 class DefaultLevelDBFactory : public LevelDBFactory { |
| 365 public: | 406 public: |
| 366 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, | 407 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, |
| 367 const LevelDBComparator* comparator, | 408 const LevelDBComparator* comparator, |
| 368 scoped_ptr<LevelDBDatabase>* db, | 409 scoped_ptr<LevelDBDatabase>* db, |
| 369 bool* is_disk_full) OVERRIDE { | 410 bool* is_disk_full) OVERRIDE { |
| 370 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); | 411 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); |
| 371 } | 412 } |
| 372 virtual bool DestroyLevelDB(const base::FilePath& file_name) OVERRIDE { | 413 virtual bool DestroyLevelDB(const FilePath& file_name) OVERRIDE { |
| 373 return LevelDBDatabase::Destroy(file_name); | 414 return LevelDBDatabase::Destroy(file_name); |
| 374 } | 415 } |
| 375 }; | 416 }; |
| 376 | 417 |
| 418 static bool GetBlobKeyGeneratorCurrentNumber( | |
| 419 LevelDBTransaction* leveldb_transaction, int64 database_id, | |
| 420 int64& blob_key_generator_current_number) { | |
|
jsbell
2013/12/18 23:04:40
Non-const ref; use pointer instead.
ericu
2013/12/19 05:19:11
Done.
| |
| 421 const std::string key_gen_key = | |
| 422 DatabaseMetaDataKey::Encode( | |
| 423 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 424 | |
| 425 // Default to initial number if not found. | |
| 426 int64 cur_number = DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber; | |
| 427 std::string data; | |
| 428 | |
| 429 bool found = false; | |
| 430 bool ok = leveldb_transaction->Get(key_gen_key, &data, &found); | |
| 431 if (!ok) { | |
| 432 INTERNAL_READ_ERROR(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 433 return false; | |
| 434 } | |
| 435 if (found) { | |
| 436 StringPiece slice(data); | |
| 437 if (!DecodeVarInt(&slice, &cur_number) || | |
|
jsbell
2013/12/18 23:04:40
Also test to see if the slice was completely consu
ericu
2013/12/19 05:19:11
Done. In GetDatabaseNames, CheckObjectStoreAndMet
jsbell
2013/12/20 00:59:28
Yes, yes, yes (although GetObjectStores is just te
ericu
2014/02/20 00:50:29
There's a weird mix of DCHECK, continue, and break
| |
| 438 !DatabaseMetaDataKey::IsValidBlobKey(cur_number)) { | |
| 439 INTERNAL_READ_ERROR(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 440 return false; | |
| 441 } | |
| 442 } | |
| 443 blob_key_generator_current_number = cur_number; | |
| 444 return true; | |
| 445 } | |
| 446 | |
| 447 static bool UpdateBlobKeyGeneratorCurrentNumber( | |
| 448 LevelDBTransaction* leveldb_transaction, int64 database_id, | |
| 449 int64 blob_key_generator_current_number) { | |
| 450 #ifndef NDEBUG | |
| 451 int64 old_number; | |
| 452 if (!GetBlobKeyGeneratorCurrentNumber(leveldb_transaction, database_id, | |
| 453 old_number)) | |
| 454 return false; | |
| 455 DCHECK_LT(old_number, blob_key_generator_current_number); | |
| 456 #endif | |
| 457 DCHECK(DatabaseMetaDataKey::IsValidBlobKey( | |
| 458 blob_key_generator_current_number)); | |
| 459 const std::string key = | |
| 460 DatabaseMetaDataKey::Encode( | |
| 461 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 462 | |
| 463 PutInt(leveldb_transaction, key, blob_key_generator_current_number); | |
| 464 return true; | |
| 465 } | |
| 466 | |
| 467 static bool DecodeBlobJournal(const std::string& data, | |
| 468 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
|
jsbell
2013/12/18 23:04:40
non-const ref; should be a pointer
ericu
2013/12/19 05:19:11
Done.
| |
| 469 // TODO(ericu): Yell something on errors. If we persistently can't read the | |
| 470 // blob journal, the safe thing to do is to clear it and leak the blobs, | |
| 471 // though that may be costly. Still, database/directory deletion should always | |
| 472 // clean things up, and we can write an fsck that will do a full correction if | |
| 473 // need be. | |
| 474 IndexedDBBackingStore::Transaction::BlobJournalType output; | |
| 475 StringPiece slice(data); | |
| 476 while (!slice.empty()) { | |
| 477 int64 database_id = -1; | |
| 478 int64 blob_key = -1; | |
| 479 if (!DecodeVarInt(&slice, &database_id)) | |
| 480 return false; | |
| 481 else if (!KeyPrefix::IsValidDatabaseId(database_id)) | |
|
jsbell
2013/12/18 23:04:40
No need for 'else' here
ericu
2013/12/19 05:19:11
Done.
| |
| 482 return false; | |
| 483 if (!DecodeVarInt(&slice, &blob_key)) { | |
| 484 return false; | |
| 485 } else if (!DatabaseMetaDataKey::IsValidBlobKey(blob_key) && | |
| 486 (blob_key != DatabaseMetaDataKey::kAllBlobsKey)) { | |
| 487 return false; | |
| 488 } | |
| 489 output.push_back(std::make_pair(database_id, blob_key)); | |
| 490 } | |
| 491 journal.swap(output); | |
| 492 return true; | |
| 493 } | |
| 494 | |
| 495 static bool GetBlobJournalHelper( | |
| 496 bool ok, bool found, | |
| 497 const std::string& data, | |
| 498 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
|
jsbell
2013/12/18 23:04:40
non-const ref
ericu
2013/12/19 05:19:11
Done.
| |
| 499 if (!ok) { | |
| 500 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); | |
| 501 return false; | |
| 502 } | |
| 503 journal.clear(); | |
| 504 if (!found) | |
| 505 return true; | |
| 506 if (!data.size()) | |
| 507 return true; | |
| 508 if (!DecodeBlobJournal(data, journal)) { | |
| 509 INTERNAL_READ_ERROR(DECODE_BLOB_JOURNAL); | |
| 510 return false; | |
| 511 } | |
| 512 return true; | |
| 513 } | |
| 514 | |
| 515 static bool GetBlobJournal( | |
| 516 const StringPiece& leveldb_key, | |
| 517 LevelDBTransaction* leveldb_transaction, | |
| 518 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
|
jsbell
2013/12/18 23:04:40
non-const ref
ericu
2013/12/19 05:19:11
Done.
| |
| 519 std::string data; | |
| 520 bool found = false; | |
| 521 bool ok = leveldb_transaction->Get(leveldb_key, &data, &found); | |
| 522 return GetBlobJournalHelper(ok, found, data, journal); | |
| 523 } | |
| 524 | |
| 525 static bool GetBlobJournal( | |
|
jsbell
2013/12/18 23:04:40
Can GetBlobJournal be a template function? Looks l
ericu
2013/12/19 05:19:11
Done.
| |
| 526 const StringPiece& leveldb_key, | |
| 527 LevelDBUncachedTransaction* leveldb_transaction, | |
| 528 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 529 std::string data; | |
| 530 bool found = false; | |
| 531 bool ok = leveldb_transaction->Get(leveldb_key, &data, &found); | |
| 532 return GetBlobJournalHelper(ok, found, data, journal); | |
| 533 } | |
| 534 | |
| 535 static std::string EncodeBlobJournalWithBlobList( | |
|
jsbell
2013/12/18 23:04:40
Does "WithBlobList" add anything meaningful to the
ericu
2013/12/19 05:19:11
Not any more. Removed.
Below it's as opposed to
| |
| 536 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 537 std::string data; | |
| 538 if (journal.size()) { | |
|
jsbell
2013/12/18 23:04:40
Nit: Probably not worth the clutter to have this t
ericu
2013/12/19 05:19:11
Done.
| |
| 539 IndexedDBBackingStore::Transaction::BlobJournalType::const_iterator iter; | |
| 540 for (iter = journal.begin(); iter != journal.end(); ++iter) { | |
| 541 EncodeVarInt(iter->first, &data); | |
| 542 EncodeVarInt(iter->second, &data); | |
| 543 } | |
| 544 } | |
| 545 return data; | |
| 546 } | |
| 547 | |
| 548 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction, | |
| 549 const std::string& level_db_key) { | |
| 550 leveldb_transaction->Remove(level_db_key); | |
| 551 } | |
| 552 | |
| 553 static void UpdatePrimaryJournalWithBlobList( | |
| 554 LevelDBTransaction* leveldb_transaction, | |
| 555 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 556 const std::string leveldbKey = BlobJournalKey::Encode(); | |
|
jsbell
2013/12/18 23:04:40
Nit: Don't use camelCase for locals/members.
ericu
2013/12/19 05:19:11
Done. This, like many of your other finds, is lef
jsbell
2013/12/20 00:59:28
I hear you. As you can see from my other patches,
| |
| 557 std::string data = EncodeBlobJournalWithBlobList(journal); | |
| 558 leveldb_transaction->Put(leveldbKey, &data); | |
| 559 } | |
| 560 | |
| 561 static void UpdateLiveBlobJournalWithBlobList( | |
| 562 LevelDBTransaction* leveldb_transaction, | |
| 563 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 564 const std::string leveldbKey = LiveBlobJournalKey::Encode(); | |
|
jsbell
2013/12/18 23:04:40
Ditto.
ericu
2013/12/19 05:19:11
Done.
| |
| 565 std::string data = EncodeBlobJournalWithBlobList(journal); | |
| 566 leveldb_transaction->Put(leveldbKey, &data); | |
| 567 } | |
| 568 | |
| 569 static bool MergeBlobsIntoLiveBlobJournal( | |
| 570 LevelDBTransaction* leveldb_transaction, | |
| 571 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 572 IndexedDBBackingStore::Transaction::BlobJournalType old_journal; | |
| 573 std::string key = LiveBlobJournalKey::Encode(); | |
| 574 if (!GetBlobJournal(key, leveldb_transaction, old_journal)) | |
| 575 return false; | |
| 576 | |
| 577 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); | |
| 578 | |
| 579 UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal); | |
| 580 return true; | |
| 581 } | |
| 582 | |
| 583 static void UpdateBlobJournalWithDatabase( | |
| 584 LevelDBUncachedTransaction* leveldb_transaction, int64 database_id) { | |
| 585 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
| 586 journal.push_back( | |
| 587 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 588 const std::string key = BlobJournalKey::Encode(); | |
| 589 std::string data = EncodeBlobJournalWithBlobList(journal); | |
| 590 leveldb_transaction->Put(key, &data); | |
| 591 } | |
| 592 | |
| 593 static bool MergeDatabaseIntoLiveBlobJournal( | |
| 594 LevelDBUncachedTransaction* leveldb_transaction, int64 database_id) { | |
| 595 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
| 596 std::string key = LiveBlobJournalKey::Encode(); | |
| 597 if (!GetBlobJournal(key, leveldb_transaction, journal)) | |
| 598 return false; | |
| 599 journal.push_back( | |
| 600 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 601 std::string data = EncodeBlobJournalWithBlobList(journal); | |
| 602 leveldb_transaction->Put(key, &data); | |
| 603 return true; | |
| 604 } | |
| 605 | |
| 606 // Blob Data is encoded as { is_file [bool], key [int64 as varInt], | |
|
jsbell
2013/12/18 23:04:40
Huh... I'm surprised that we need to distinguish f
ericu
2013/12/19 05:19:11
It's partly for spec correctness in a way I haven'
jsbell
2013/12/20 00:59:28
Thanks I hadn't considered that things other than
| |
| 607 // type [string-with-length, may be empty], then [for Blobs] size | |
| 608 // [int64 as varInt] or [for Files] fileName [string-with-length] } | |
| 609 static std::string EncodeBlobData( | |
| 610 const std::vector<IndexedDBBlobInfo*>& blob_info) { | |
| 611 std::string ret; | |
| 612 std::vector<IndexedDBBlobInfo*>::const_iterator iter; | |
| 613 for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) { | |
| 614 const IndexedDBBlobInfo& info = **iter; | |
| 615 EncodeBool(info.is_file(), &ret); | |
| 616 EncodeVarInt(info.key(), &ret); | |
| 617 EncodeStringWithLength(info.type(), &ret); | |
| 618 if (info.is_file()) | |
| 619 EncodeStringWithLength(info.file_name(), &ret); | |
| 620 else | |
| 621 EncodeVarInt(info.size(), &ret); | |
| 622 } | |
| 623 return ret; | |
| 624 } | |
| 625 | |
| 626 static bool DecodeBlobData( | |
| 627 const std::string& data, | |
| 628 std::vector<IndexedDBBlobInfo>* output) { | |
| 629 std::vector<IndexedDBBlobInfo> ret; | |
| 630 output->clear(); | |
| 631 StringPiece slice(data); | |
| 632 while (!slice.empty()) { | |
| 633 bool is_file; | |
| 634 int64 key; | |
| 635 string16 type; | |
| 636 int64 size; | |
| 637 string16 file_name; | |
| 638 | |
| 639 if (!DecodeBool(&slice, &is_file)) | |
| 640 return false; | |
| 641 if (!DecodeVarInt(&slice, &key) || | |
| 642 !DatabaseMetaDataKey::IsValidBlobKey(key)) | |
| 643 return false; | |
| 644 if (!DecodeStringWithLength(&slice, &type)) | |
| 645 return false; | |
| 646 if (is_file) { | |
| 647 if (!DecodeStringWithLength(&slice, &file_name)) | |
| 648 return false; | |
| 649 ret.push_back(IndexedDBBlobInfo(key, type, file_name)); | |
| 650 } else { | |
| 651 if (!DecodeVarInt(&slice, &size) || size < 0) | |
| 652 return false; | |
| 653 ret.push_back(IndexedDBBlobInfo(type, static_cast<uint64>(size), key)); | |
| 654 } | |
| 655 } | |
| 656 output->swap(ret); | |
| 657 | |
| 658 return true; | |
| 659 } | |
| 660 | |
| 377 IndexedDBBackingStore::IndexedDBBackingStore( | 661 IndexedDBBackingStore::IndexedDBBackingStore( |
| 662 IndexedDBFactory* indexed_db_factory, | |
| 378 const GURL& origin_url, | 663 const GURL& origin_url, |
| 664 const FilePath& blob_path, | |
| 665 net::URLRequestContext* request_context, | |
| 379 scoped_ptr<LevelDBDatabase> db, | 666 scoped_ptr<LevelDBDatabase> db, |
| 380 scoped_ptr<LevelDBComparator> comparator) | 667 scoped_ptr<LevelDBComparator> comparator, |
| 381 : origin_url_(origin_url), | 668 base::TaskRunner* task_runner) |
| 669 : indexed_db_factory_(indexed_db_factory), | |
| 670 origin_url_(origin_url), | |
| 382 origin_identifier_(ComputeOriginIdentifier(origin_url)), | 671 origin_identifier_(ComputeOriginIdentifier(origin_url)), |
| 672 blob_path_(blob_path), | |
| 673 request_context_(request_context), | |
| 674 task_runner_(task_runner), | |
| 383 db_(db.Pass()), | 675 db_(db.Pass()), |
| 384 comparator_(comparator.Pass()) {} | 676 comparator_(comparator.Pass()), |
| 677 active_blob_registry_(this) {} | |
| 385 | 678 |
| 386 IndexedDBBackingStore::~IndexedDBBackingStore() { | 679 IndexedDBBackingStore::~IndexedDBBackingStore() { |
| 680 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { | |
| 681 ChildProcessSecurityPolicyImpl* policy = | |
| 682 ChildProcessSecurityPolicyImpl::GetInstance(); | |
| 683 for (std::set<int>::iterator iter = child_process_ids_granted_.begin(); | |
| 684 iter != child_process_ids_granted_.end(); ++iter) { | |
| 685 policy->RevokeAllPermissionsForFile(*iter, blob_path_); | |
| 686 } | |
| 687 } | |
| 387 // db_'s destructor uses comparator_. The order of destruction is important. | 688 // db_'s destructor uses comparator_. The order of destruction is important. |
| 388 db_.reset(); | 689 db_.reset(); |
| 389 comparator_.reset(); | 690 comparator_.reset(); |
| 390 } | 691 } |
| 391 | 692 |
| 392 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( | 693 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( |
| 393 const std::string& primary_key, | 694 const std::string& primary_key, |
| 394 int64 version) | 695 int64 version) |
| 395 : primary_key_(primary_key), version_(version) { | 696 : primary_key_(primary_key), version_(version) { |
| 396 DCHECK(!primary_key.empty()); | 697 DCHECK(!primary_key.empty()); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 415 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, | 716 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, |
| 416 INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, | 717 INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, |
| 417 INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED, | 718 INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED, |
| 418 INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, | 719 INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, |
| 419 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, | 720 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, |
| 420 INDEXED_DB_BACKING_STORE_OPEN_MAX, | 721 INDEXED_DB_BACKING_STORE_OPEN_MAX, |
| 421 }; | 722 }; |
| 422 | 723 |
| 423 // static | 724 // static |
| 424 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 725 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
| 726 IndexedDBFactory* indexed_db_factory, | |
| 425 const GURL& origin_url, | 727 const GURL& origin_url, |
| 426 const base::FilePath& path_base, | 728 const base::FilePath& path_base, |
| 729 net::URLRequestContext* request_context, | |
| 427 blink::WebIDBDataLoss* data_loss, | 730 blink::WebIDBDataLoss* data_loss, |
| 428 std::string* data_loss_message, | 731 std::string* data_loss_message, |
| 429 bool* disk_full) { | 732 bool* disk_full, |
| 733 base::TaskRunner* task_runner, | |
| 734 bool clean_journal) { | |
| 430 *data_loss = blink::WebIDBDataLossNone; | 735 *data_loss = blink::WebIDBDataLossNone; |
| 431 DefaultLevelDBFactory leveldb_factory; | 736 DefaultLevelDBFactory leveldb_factory; |
| 432 return IndexedDBBackingStore::Open(origin_url, | 737 return IndexedDBBackingStore::Open(indexed_db_factory, |
| 738 origin_url, | |
| 433 path_base, | 739 path_base, |
| 740 request_context, | |
| 434 data_loss, | 741 data_loss, |
| 435 data_loss_message, | 742 data_loss_message, |
| 436 disk_full, | 743 disk_full, |
| 437 &leveldb_factory); | 744 &leveldb_factory, |
| 745 task_runner, | |
| 746 clean_journal); | |
| 438 } | 747 } |
| 439 | 748 |
| 440 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { | 749 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { |
| 441 if (origin_url.host() == "docs.google.com") | 750 if (origin_url.host() == "docs.google.com") |
| 442 return ".Docs"; | 751 return ".Docs"; |
| 443 return std::string(); | 752 return std::string(); |
| 444 } | 753 } |
| 445 | 754 |
| 446 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, | 755 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, |
| 447 const GURL& origin_url) { | 756 const GURL& origin_url) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 488 min, | 797 min, |
| 489 max, | 798 max, |
| 490 num_buckets); | 799 num_buckets); |
| 491 return true; | 800 return true; |
| 492 } | 801 } |
| 493 return false; | 802 return false; |
| 494 } | 803 } |
| 495 | 804 |
| 496 // static | 805 // static |
| 497 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 806 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
| 807 IndexedDBFactory* indexed_db_factory, | |
| 498 const GURL& origin_url, | 808 const GURL& origin_url, |
| 499 const base::FilePath& path_base, | 809 const base::FilePath& path_base, |
| 810 net::URLRequestContext* request_context, | |
| 500 blink::WebIDBDataLoss* data_loss, | 811 blink::WebIDBDataLoss* data_loss, |
| 501 std::string* data_loss_message, | 812 std::string* data_loss_message, |
| 502 bool* is_disk_full, | 813 bool* is_disk_full, |
| 503 LevelDBFactory* leveldb_factory) { | 814 LevelDBFactory* leveldb_factory, |
| 815 base::TaskRunner* task_runner, | |
| 816 bool clean_journal) { | |
| 504 IDB_TRACE("IndexedDBBackingStore::Open"); | 817 IDB_TRACE("IndexedDBBackingStore::Open"); |
| 505 DCHECK(!path_base.empty()); | 818 DCHECK(!path_base.empty()); |
| 506 *data_loss = blink::WebIDBDataLossNone; | 819 *data_loss = blink::WebIDBDataLossNone; |
| 507 *data_loss_message = ""; | 820 *data_loss_message = ""; |
| 508 *is_disk_full = false; | 821 *is_disk_full = false; |
| 509 | 822 |
| 510 scoped_ptr<LevelDBComparator> comparator(new Comparator()); | 823 scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
| 511 | 824 |
| 512 if (!IsStringASCII(path_base.AsUTF8Unsafe())) { | 825 if (!IsStringASCII(path_base.AsUTF8Unsafe())) { |
| 513 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, | 826 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, |
| 514 origin_url); | 827 origin_url); |
| 515 } | 828 } |
| 516 if (!file_util::CreateDirectory(path_base)) { | 829 if (!file_util::CreateDirectory(path_base)) { |
| 517 LOG(ERROR) << "Unable to create IndexedDB database path " | 830 LOG(ERROR) << "Unable to create IndexedDB database path " |
| 518 << path_base.AsUTF8Unsafe(); | 831 << path_base.AsUTF8Unsafe(); |
| 519 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, | 832 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, |
| 520 origin_url); | 833 origin_url); |
| 521 return scoped_refptr<IndexedDBBackingStore>(); | 834 return scoped_refptr<IndexedDBBackingStore>(); |
| 522 } | 835 } |
| 523 | 836 |
| 524 const base::FilePath file_path = | 837 const base::FilePath file_path = |
| 525 path_base.Append(ComputeFileName(origin_url)); | 838 path_base.Append(ComputeFileName(origin_url)); |
| 839 const base::FilePath blob_path = | |
| 840 path_base.Append(ComputeBlobPath(origin_url)); | |
| 526 | 841 |
| 527 if (IsPathTooLong(file_path)) { | 842 if (IsPathTooLong(file_path)) { |
| 528 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, | 843 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, |
| 529 origin_url); | 844 origin_url); |
| 530 return scoped_refptr<IndexedDBBackingStore>(); | 845 return scoped_refptr<IndexedDBBackingStore>(); |
| 531 } | 846 } |
| 532 | 847 |
| 533 scoped_ptr<LevelDBDatabase> db; | 848 scoped_ptr<LevelDBDatabase> db; |
| 534 leveldb::Status status = leveldb_factory->OpenLevelDB( | 849 leveldb::Status status = leveldb_factory->OpenLevelDB( |
| 535 file_path, comparator.get(), &db, is_disk_full); | 850 file_path, comparator.get(), &db, is_disk_full); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 origin_url); | 915 origin_url); |
| 601 } | 916 } |
| 602 | 917 |
| 603 if (!db) { | 918 if (!db) { |
| 604 NOTREACHED(); | 919 NOTREACHED(); |
| 605 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, | 920 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, |
| 606 origin_url); | 921 origin_url); |
| 607 return scoped_refptr<IndexedDBBackingStore>(); | 922 return scoped_refptr<IndexedDBBackingStore>(); |
| 608 } | 923 } |
| 609 | 924 |
| 610 return Create(origin_url, db.Pass(), comparator.Pass()); | 925 scoped_refptr<IndexedDBBackingStore> backing_store = Create( |
| 926 indexed_db_factory, origin_url, blob_path, request_context, db.Pass(), | |
| 927 comparator.Pass(), task_runner); | |
| 928 | |
| 929 if (clean_journal && !backing_store->CleanUpBlobJournal( | |
| 930 LiveBlobJournalKey::Encode())) | |
| 931 return scoped_refptr<IndexedDBBackingStore>(); | |
| 932 return backing_store; | |
| 611 } | 933 } |
| 612 | 934 |
| 613 // static | 935 // static |
| 614 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 936 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
| 615 const GURL& origin_url) { | 937 const GURL& origin_url, base::TaskRunner* task_runner) { |
| 616 DefaultLevelDBFactory leveldb_factory; | 938 DefaultLevelDBFactory leveldb_factory; |
| 617 return IndexedDBBackingStore::OpenInMemory(origin_url, &leveldb_factory); | 939 return IndexedDBBackingStore::OpenInMemory(origin_url, &leveldb_factory, |
| 940 task_runner); | |
| 618 } | 941 } |
| 619 | 942 |
| 620 // static | 943 // static |
| 621 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 944 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
| 622 const GURL& origin_url, | 945 const GURL& origin_url, |
| 623 LevelDBFactory* leveldb_factory) { | 946 LevelDBFactory* leveldb_factory, |
| 947 base::TaskRunner* task_runner) { | |
| 624 IDB_TRACE("IndexedDBBackingStore::OpenInMemory"); | 948 IDB_TRACE("IndexedDBBackingStore::OpenInMemory"); |
| 625 | 949 |
| 626 scoped_ptr<LevelDBComparator> comparator(new Comparator()); | 950 scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
| 627 scoped_ptr<LevelDBDatabase> db = | 951 scoped_ptr<LevelDBDatabase> db = |
| 628 LevelDBDatabase::OpenInMemory(comparator.get()); | 952 LevelDBDatabase::OpenInMemory(comparator.get()); |
| 629 if (!db) { | 953 if (!db) { |
| 630 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; | 954 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; |
| 631 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, | 955 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, |
| 632 origin_url); | 956 origin_url); |
| 633 return scoped_refptr<IndexedDBBackingStore>(); | 957 return scoped_refptr<IndexedDBBackingStore>(); |
| 634 } | 958 } |
| 635 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); | 959 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); |
| 636 | 960 |
| 637 return Create(origin_url, db.Pass(), comparator.Pass()); | 961 return Create(NULL, origin_url, FilePath(), NULL, db.Pass(), |
| 962 comparator.Pass(), task_runner); | |
| 638 } | 963 } |
| 639 | 964 |
| 640 // static | 965 // static |
| 641 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( | 966 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( |
| 967 IndexedDBFactory* indexed_db_factory, | |
| 642 const GURL& origin_url, | 968 const GURL& origin_url, |
| 969 const FilePath& blob_path, | |
| 970 net::URLRequestContext* request_context, | |
| 643 scoped_ptr<LevelDBDatabase> db, | 971 scoped_ptr<LevelDBDatabase> db, |
| 644 scoped_ptr<LevelDBComparator> comparator) { | 972 scoped_ptr<LevelDBComparator> comparator, |
| 973 base::TaskRunner* task_runner) { | |
| 645 // TODO(jsbell): Handle comparator name changes. | 974 // TODO(jsbell): Handle comparator name changes. |
| 646 | |
| 647 scoped_refptr<IndexedDBBackingStore> backing_store( | 975 scoped_refptr<IndexedDBBackingStore> backing_store( |
| 648 new IndexedDBBackingStore(origin_url, db.Pass(), comparator.Pass())); | 976 new IndexedDBBackingStore(indexed_db_factory, origin_url, blob_path, |
| 649 if (!SetUpMetadata(backing_store->db_.get(), | 977 request_context, db.Pass(), comparator.Pass(), task_runner)); |
| 650 backing_store->origin_identifier_)) | 978 if (!backing_store->SetUpMetadata()) |
| 651 return scoped_refptr<IndexedDBBackingStore>(); | 979 return scoped_refptr<IndexedDBBackingStore>(); |
| 652 | 980 |
| 653 return backing_store; | 981 return backing_store; |
| 654 } | 982 } |
| 655 | 983 |
| 984 void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) { | |
| 985 if (!child_process_ids_granted_.count(child_process_id)) { | |
| 986 child_process_ids_granted_.insert(child_process_id); | |
| 987 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( | |
| 988 child_process_id, blob_path_); | |
| 989 } | |
| 990 } | |
| 991 | |
| 656 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() { | 992 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() { |
| 657 std::vector<string16> found_names; | 993 std::vector<string16> found_names; |
| 658 const std::string start_key = | 994 const std::string start_key = |
| 659 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); | 995 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); |
| 660 const std::string stop_key = | 996 const std::string stop_key = |
| 661 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); | 997 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); |
| 662 | 998 |
| 663 DCHECK(found_names.empty()); | 999 DCHECK(found_names.empty()); |
| 664 | 1000 |
| 665 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 1001 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 723 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) | 1059 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) |
| 724 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; | 1060 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; |
| 725 | 1061 |
| 726 ok = GetMaxObjectStoreId( | 1062 ok = GetMaxObjectStoreId( |
| 727 db_.get(), metadata->id, &metadata->max_object_store_id); | 1063 db_.get(), metadata->id, &metadata->max_object_store_id); |
| 728 if (!ok) { | 1064 if (!ok) { |
| 729 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); | 1065 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); |
| 730 return false; | 1066 return false; |
| 731 } | 1067 } |
| 732 | 1068 |
| 1069 int64 blob_key_generator_current_number = | |
| 1070 DatabaseMetaDataKey::kInvalidBlobKey; | |
| 1071 | |
| 1072 ok = GetVarInt(db_.get(), | |
| 1073 DatabaseMetaDataKey::Encode( | |
| 1074 metadata->id, | |
| 1075 DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), | |
| 1076 &blob_key_generator_current_number, | |
| 1077 found); | |
| 1078 if (!ok) { | |
| 1079 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); | |
| 1080 return false; | |
| 1081 } | |
| 1082 if (!*found) { | |
| 1083 // This database predates blob support. | |
| 1084 *found = true; | |
| 1085 } else if (!DatabaseMetaDataKey::IsValidBlobKey( | |
| 1086 blob_key_generator_current_number)) { | |
| 1087 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); | |
| 1088 return false; | |
| 1089 } | |
| 1090 | |
| 733 return true; | 1091 return true; |
| 734 } | 1092 } |
| 735 | 1093 |
| 736 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBTransaction* transaction, | 1094 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBTransaction* transaction, |
| 737 int64* new_id) { | 1095 int64* new_id) { |
| 738 *new_id = -1; | 1096 *new_id = -1; |
| 739 int64 max_database_id = -1; | 1097 int64 max_database_id = -1; |
| 740 bool found = false; | 1098 bool found = false; |
| 741 bool ok = | 1099 bool ok = |
| 742 GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found); | 1100 GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 774 DatabaseNameKey::Encode(origin_identifier_, name), | 1132 DatabaseNameKey::Encode(origin_identifier_, name), |
| 775 *row_id); | 1133 *row_id); |
| 776 PutString( | 1134 PutString( |
| 777 transaction.get(), | 1135 transaction.get(), |
| 778 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), | 1136 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), |
| 779 version); | 1137 version); |
| 780 PutVarInt(transaction.get(), | 1138 PutVarInt(transaction.get(), |
| 781 DatabaseMetaDataKey::Encode(*row_id, | 1139 DatabaseMetaDataKey::Encode(*row_id, |
| 782 DatabaseMetaDataKey::USER_INT_VERSION), | 1140 DatabaseMetaDataKey::USER_INT_VERSION), |
| 783 int_version); | 1141 int_version); |
| 1142 PutVarInt( | |
| 1143 transaction.get(), | |
| 1144 DatabaseMetaDataKey::Encode(*row_id, | |
| 1145 DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), | |
| 1146 DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber); | |
| 784 if (!transaction->Commit()) { | 1147 if (!transaction->Commit()) { |
| 785 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); | 1148 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); |
| 786 return false; | 1149 return false; |
| 787 } | 1150 } |
| 788 return true; | 1151 return true; |
| 789 } | 1152 } |
| 790 | 1153 |
| 791 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( | 1154 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( |
| 792 IndexedDBBackingStore::Transaction* transaction, | 1155 IndexedDBBackingStore::Transaction* transaction, |
| 793 int64 row_id, | 1156 int64 row_id, |
| 794 int64 int_version) { | 1157 int64 int_version) { |
| 795 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) | 1158 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) |
| 796 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; | 1159 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; |
| 797 DCHECK_GE(int_version, 0) << "int_version was " << int_version; | 1160 DCHECK_GE(int_version, 0) << "int_version was " << int_version; |
| 798 PutVarInt(transaction->transaction(), | 1161 PutVarInt(transaction->transaction(), |
| 799 DatabaseMetaDataKey::Encode(row_id, | 1162 DatabaseMetaDataKey::Encode(row_id, |
| 800 DatabaseMetaDataKey::USER_INT_VERSION), | 1163 DatabaseMetaDataKey::USER_INT_VERSION), |
| 801 int_version); | 1164 int_version); |
| 802 return true; | 1165 return true; |
| 803 } | 1166 } |
| 804 | 1167 |
| 805 static void DeleteRange(LevelDBTransaction* transaction, | 1168 // Note that if you're deleting a range that contains user keys that have blob |
| 806 const std::string& begin, | 1169 // info, this won't clean up the blobs. |
| 807 const std::string& end) { | 1170 static void DeleteRangeByKeys(LevelDBTransaction* transaction, |
| 1171 const std::string& begin, | |
| 1172 const std::string& end) { | |
| 808 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); | 1173 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); |
| 809 for (it->Seek(begin); it->IsValid() && CompareKeys(it->Key(), end) < 0; | 1174 for (it->Seek(begin); it->IsValid() && CompareKeys(it->Key(), end) < 0; |
| 810 it->Next()) | 1175 it->Next()) |
| 811 transaction->Remove(it->Key()); | 1176 transaction->Remove(it->Key()); |
| 812 } | 1177 } |
| 813 | 1178 |
| 1179 // For a whole-object-store deletion, we still use the one-blob-record-at-a-time | |
| 1180 // deletion mechanism designed for normal transactions. We could go with the | |
| 1181 // nuke-the-whole-directory method used for deleteDatabase if we structured the | |
| 1182 // directories accordingly, but that would complicate the kind of info we store | |
| 1183 // in the LevelDBTransaction and lengthen paths. | |
| 1184 static void DeleteBlobsInObjectStore( | |
| 1185 IndexedDBBackingStore::Transaction* transaction, | |
| 1186 int64 database_id, int64 object_store_id) { | |
| 1187 std::string start_key, end_key; | |
| 1188 start_key = | |
| 1189 BlobEntryKey::EncodeMinForObjectStore(database_id, object_store_id); | |
| 1190 end_key = | |
| 1191 BlobEntryKey::EncodeMaxForObjectStore(database_id, object_store_id); | |
| 1192 | |
| 1193 scoped_ptr<LevelDBIterator> it = | |
| 1194 transaction->transaction()->CreateIterator(); | |
| 1195 for (it->Seek(start_key); | |
| 1196 it->IsValid() && CompareKeys(it->Key(), end_key) < 0; it->Next()) { | |
| 1197 StringPiece key_piece(it->Key()); | |
| 1198 std::string user_key = | |
| 1199 BlobEntryKey::ReencodeToObjectStoreDataKey(&key_piece); | |
| 1200 if (user_key.size()) | |
| 1201 transaction->PutBlobInfo(database_id, object_store_id, user_key, NULL, | |
| 1202 NULL); | |
| 1203 else | |
| 1204 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); | |
|
jsbell
2013/12/18 23:04:40
Intentionally keep going in case of error here?
M
ericu
2013/12/19 05:19:11
Actually, we should stop on error. Fixed.
| |
| 1205 } | |
| 1206 } | |
| 1207 | |
| 1208 static bool GetBlobInfoForRecord( | |
| 1209 IndexedDBBackingStore* backing_store, | |
| 1210 LevelDBTransaction* leveldb_transaction, | |
| 1211 int64 database_id, | |
| 1212 const std::string& leveldb_key, | |
| 1213 IndexedDBValue* value) { | |
| 1214 | |
| 1215 BlobEntryKey blob_entry_key; | |
| 1216 StringPiece leveldb_key_piece(leveldb_key); | |
| 1217 if (!BlobEntryKey::FromObjectStoreDataKey( | |
| 1218 &leveldb_key_piece, &blob_entry_key)) { | |
| 1219 NOTREACHED(); | |
| 1220 return false; | |
| 1221 } | |
| 1222 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); | |
| 1223 std::string encoded_key = blob_entry_key.Encode(); | |
| 1224 it->Seek(encoded_key); | |
| 1225 if (it->IsValid() && CompareKeys(it->Key(), encoded_key) == 0) { | |
| 1226 if (!DecodeBlobData(it->Value().as_string(), &value->blob_info)) { | |
| 1227 INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD); | |
| 1228 return false; | |
| 1229 } | |
| 1230 std::vector<IndexedDBBlobInfo>::iterator iter; | |
| 1231 for (iter = value->blob_info.begin(); iter != value->blob_info.end(); | |
| 1232 ++iter) { | |
| 1233 iter->set_file_path( | |
| 1234 backing_store->GetIDBBlobFileName(database_id, iter->key())); | |
| 1235 iter->set_mark_used_callback( | |
| 1236 backing_store->active_blob_registry()->GetAddBlobRefCallback( | |
| 1237 database_id, iter->key())); | |
| 1238 iter->set_release_callback( | |
| 1239 backing_store->active_blob_registry()->GetFinalReleaseCallback( | |
| 1240 database_id, iter->key())); | |
| 1241 if (iter->is_file()) { | |
| 1242 base::PlatformFileInfo info; | |
| 1243 if (file_util::GetFileInfo(iter->file_path(), &info)) { | |
| 1244 // This should always work, but it isn't fatal if it doesn't; it just | |
| 1245 // means a potential slow synchronous call from the renderer later. | |
| 1246 iter->set_last_modified(info.last_modified); | |
| 1247 iter->set_size(info.size); | |
| 1248 } | |
| 1249 } | |
| 1250 } | |
| 1251 } | |
| 1252 return true; | |
| 1253 } | |
| 1254 | |
| 814 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) { | 1255 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) { |
| 815 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); | 1256 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); |
| 816 scoped_ptr<LevelDBWriteOnlyTransaction> transaction = | 1257 scoped_ptr<LevelDBUncachedTransaction> transaction = |
| 817 LevelDBWriteOnlyTransaction::Create(db_.get()); | 1258 LevelDBUncachedTransaction::Create(db_.get()); |
| 1259 | |
| 1260 if (!CleanUpBlobJournal(BlobJournalKey::Encode())) | |
| 1261 return false; | |
| 818 | 1262 |
| 819 IndexedDBDatabaseMetadata metadata; | 1263 IndexedDBDatabaseMetadata metadata; |
| 820 bool success = false; | 1264 bool success = false; |
| 821 bool ok = GetIDBDatabaseMetaData(name, &metadata, &success); | 1265 bool ok = GetIDBDatabaseMetaData(name, &metadata, &success); |
| 822 if (!ok) | 1266 if (!ok) |
| 823 return false; | 1267 return false; |
| 824 if (!success) | 1268 if (!success) |
| 825 return true; | 1269 return true; |
| 826 | 1270 |
| 827 const std::string start_key = DatabaseMetaDataKey::Encode( | 1271 const std::string start_key = DatabaseMetaDataKey::Encode( |
| 828 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); | 1272 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); |
| 829 const std::string stop_key = DatabaseMetaDataKey::Encode( | 1273 const std::string stop_key = DatabaseMetaDataKey::Encode( |
| 830 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); | 1274 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); |
| 831 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 1275 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
| 832 for (it->Seek(start_key); | 1276 for (it->Seek(start_key); |
| 833 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; | 1277 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; |
| 834 it->Next()) | 1278 it->Next()) |
| 835 transaction->Remove(it->Key()); | 1279 transaction->Remove(it->Key()); |
| 836 | 1280 |
| 837 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); | 1281 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); |
| 838 transaction->Remove(key); | 1282 transaction->Remove(key); |
| 839 | 1283 |
| 1284 bool need_cleanup = false; | |
| 1285 if (active_blob_registry()->MarkDeletedCheckIfUsed( | |
| 1286 metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) { | |
| 1287 if (!MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id)) | |
| 1288 return false; | |
| 1289 } else { | |
| 1290 UpdateBlobJournalWithDatabase(transaction.get(), metadata.id); | |
| 1291 need_cleanup = true; | |
| 1292 } | |
| 1293 | |
| 840 if (!transaction->Commit()) { | 1294 if (!transaction->Commit()) { |
| 841 INTERNAL_WRITE_ERROR(DELETE_DATABASE); | 1295 INTERNAL_WRITE_ERROR(DELETE_DATABASE); |
| 842 return false; | 1296 return false; |
| 843 } | 1297 } |
| 1298 | |
| 1299 if (need_cleanup) | |
| 1300 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 1301 | |
| 844 return true; | 1302 return true; |
| 845 } | 1303 } |
| 846 | 1304 |
| 847 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, | 1305 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, |
| 848 const std::string& stop_key, | 1306 const std::string& stop_key, |
| 849 int64 object_store_id, | 1307 int64 object_store_id, |
| 850 int64 meta_data_type) { | 1308 int64 meta_data_type) { |
| 851 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 1309 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
| 852 return false; | 1310 return false; |
| 853 | 1311 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 926 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1384 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
| 927 break; | 1385 break; |
| 928 } | 1386 } |
| 929 bool auto_increment; | 1387 bool auto_increment; |
| 930 { | 1388 { |
| 931 StringPiece slice(it->Value()); | 1389 StringPiece slice(it->Value()); |
| 932 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) | 1390 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) |
| 933 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1391 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
| 934 } | 1392 } |
| 935 | 1393 |
| 936 it->Next(); // Is evicatble. | 1394 it->Next(); // Is evictable. |
| 937 if (!CheckObjectStoreAndMetaDataType(it.get(), | 1395 if (!CheckObjectStoreAndMetaDataType(it.get(), |
| 938 stop_key, | 1396 stop_key, |
| 939 object_store_id, | 1397 object_store_id, |
| 940 ObjectStoreMetaDataKey::EVICTABLE)) { | 1398 ObjectStoreMetaDataKey::EVICTABLE)) { |
| 941 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1399 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
| 942 break; | 1400 break; |
| 943 } | 1401 } |
| 944 | 1402 |
| 945 it->Next(); // Last version. | 1403 it->Next(); // Last version. |
| 946 if (!CheckObjectStoreAndMetaDataType( | 1404 if (!CheckObjectStoreAndMetaDataType( |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1113 &found); | 1571 &found); |
| 1114 if (!ok) { | 1572 if (!ok) { |
| 1115 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); | 1573 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); |
| 1116 return false; | 1574 return false; |
| 1117 } | 1575 } |
| 1118 if (!found) { | 1576 if (!found) { |
| 1119 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); | 1577 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); |
| 1120 return false; | 1578 return false; |
| 1121 } | 1579 } |
| 1122 | 1580 |
| 1123 DeleteRange( | 1581 DeleteBlobsInObjectStore(transaction, database_id, object_store_id); |
| 1582 DeleteRangeByKeys( | |
| 1124 leveldb_transaction, | 1583 leveldb_transaction, |
| 1125 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), | 1584 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), |
| 1126 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | 1585 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); |
| 1127 | 1586 |
| 1128 leveldb_transaction->Remove( | 1587 leveldb_transaction->Remove( |
| 1129 ObjectStoreNamesKey::Encode(database_id, object_store_name)); | 1588 ObjectStoreNamesKey::Encode(database_id, object_store_name)); |
| 1130 | 1589 |
| 1131 DeleteRange(leveldb_transaction, | 1590 DeleteRangeByKeys( |
| 1132 IndexFreeListKey::Encode(database_id, object_store_id, 0), | 1591 leveldb_transaction, |
| 1133 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); | 1592 IndexFreeListKey::Encode(database_id, object_store_id, 0), |
| 1134 DeleteRange(leveldb_transaction, | 1593 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); |
| 1135 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), | 1594 DeleteRangeByKeys( |
| 1136 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | 1595 leveldb_transaction, |
| 1596 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), | |
| 1597 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | |
| 1137 | 1598 |
| 1138 return ClearObjectStore(transaction, database_id, object_store_id); | 1599 return ClearObjectStore(transaction, database_id, object_store_id); |
| 1139 } | 1600 } |
| 1140 | 1601 |
| 1141 bool IndexedDBBackingStore::GetRecord( | 1602 bool IndexedDBBackingStore::GetRecord( |
| 1142 IndexedDBBackingStore::Transaction* transaction, | 1603 IndexedDBBackingStore::Transaction* transaction, |
| 1143 int64 database_id, | 1604 int64 database_id, |
| 1144 int64 object_store_id, | 1605 int64 object_store_id, |
| 1145 const IndexedDBKey& key, | 1606 const IndexedDBKey& key, |
| 1146 std::string* record) { | 1607 IndexedDBValue* record) { |
| 1147 IDB_TRACE("IndexedDBBackingStore::GetRecord"); | 1608 IDB_TRACE("IndexedDBBackingStore::GetRecord"); |
| 1148 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1609 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
| 1149 return false; | 1610 return false; |
| 1150 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1611 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 1151 | 1612 |
| 1152 const std::string leveldb_key = | 1613 const std::string leveldb_key = |
| 1153 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 1614 ObjectStoreDataKey::Encode(database_id, object_store_id, key); |
| 1154 std::string data; | 1615 std::string data; |
| 1155 | 1616 |
| 1156 record->clear(); | 1617 record->clear(); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1168 return false; | 1629 return false; |
| 1169 } | 1630 } |
| 1170 | 1631 |
| 1171 int64 version; | 1632 int64 version; |
| 1172 StringPiece slice(data); | 1633 StringPiece slice(data); |
| 1173 if (!DecodeVarInt(&slice, &version)) { | 1634 if (!DecodeVarInt(&slice, &version)) { |
| 1174 INTERNAL_READ_ERROR(GET_RECORD); | 1635 INTERNAL_READ_ERROR(GET_RECORD); |
| 1175 return false; | 1636 return false; |
| 1176 } | 1637 } |
| 1177 | 1638 |
| 1178 *record = slice.as_string(); | 1639 record->bits = slice.as_string(); |
| 1179 return true; | 1640 return GetBlobInfoForRecord( |
| 1641 this, leveldb_transaction, database_id, leveldb_key, record); | |
| 1180 } | 1642 } |
| 1181 | 1643 |
| 1182 WARN_UNUSED_RESULT static bool GetNewVersionNumber( | 1644 WARN_UNUSED_RESULT static bool GetNewVersionNumber( |
| 1183 LevelDBTransaction* transaction, | 1645 LevelDBTransaction* transaction, |
| 1184 int64 database_id, | 1646 int64 database_id, |
| 1185 int64 object_store_id, | 1647 int64 object_store_id, |
| 1186 int64* new_version_number) { | 1648 int64* new_version_number) { |
| 1187 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( | 1649 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( |
| 1188 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); | 1650 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); |
| 1189 | 1651 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1208 | 1670 |
| 1209 *new_version_number = version; | 1671 *new_version_number = version; |
| 1210 return true; | 1672 return true; |
| 1211 } | 1673 } |
| 1212 | 1674 |
| 1213 bool IndexedDBBackingStore::PutRecord( | 1675 bool IndexedDBBackingStore::PutRecord( |
| 1214 IndexedDBBackingStore::Transaction* transaction, | 1676 IndexedDBBackingStore::Transaction* transaction, |
| 1215 int64 database_id, | 1677 int64 database_id, |
| 1216 int64 object_store_id, | 1678 int64 object_store_id, |
| 1217 const IndexedDBKey& key, | 1679 const IndexedDBKey& key, |
| 1218 const std::string& value, | 1680 IndexedDBValue& value, |
| 1681 ScopedVector<webkit_blob::BlobDataHandle>* handles, | |
| 1219 RecordIdentifier* record_identifier) { | 1682 RecordIdentifier* record_identifier) { |
| 1220 IDB_TRACE("IndexedDBBackingStore::PutRecord"); | 1683 IDB_TRACE("IndexedDBBackingStore::PutRecord"); |
| 1221 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1684 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
| 1222 return false; | 1685 return false; |
| 1223 DCHECK(key.IsValid()); | 1686 DCHECK(key.IsValid()); |
| 1224 | 1687 |
| 1225 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1688 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 1226 int64 version = -1; | 1689 int64 version = -1; |
| 1227 bool ok = GetNewVersionNumber( | 1690 bool ok = GetNewVersionNumber( |
| 1228 leveldb_transaction, database_id, object_store_id, &version); | 1691 leveldb_transaction, database_id, object_store_id, &version); |
| 1229 if (!ok) | 1692 if (!ok) |
| 1230 return false; | 1693 return false; |
| 1231 DCHECK_GE(version, 0); | 1694 DCHECK_GE(version, 0); |
| 1232 const std::string object_storedata_key = | 1695 const std::string object_store_data_key = |
| 1233 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 1696 ObjectStoreDataKey::Encode(database_id, object_store_id, key); |
| 1234 | 1697 |
| 1235 std::string v; | 1698 std::string v; |
| 1236 EncodeVarInt(version, &v); | 1699 EncodeVarInt(version, &v); |
| 1237 v.append(value); | 1700 v.append(value.bits); |
| 1238 | 1701 |
| 1239 leveldb_transaction->Put(object_storedata_key, &v); | 1702 leveldb_transaction->Put(object_store_data_key, &v); |
| 1703 transaction->PutBlobInfo(database_id, object_store_id, object_store_data_key, | |
| 1704 &value.blob_info, handles); | |
| 1705 DCHECK(!handles->size()); | |
| 1240 | 1706 |
| 1241 const std::string exists_entry_key = | 1707 const std::string exists_entry_key = |
| 1242 ExistsEntryKey::Encode(database_id, object_store_id, key); | 1708 ExistsEntryKey::Encode(database_id, object_store_id, key); |
| 1243 std::string version_encoded; | 1709 std::string version_encoded; |
| 1244 EncodeInt(version, &version_encoded); | 1710 EncodeInt(version, &version_encoded); |
| 1245 leveldb_transaction->Put(exists_entry_key, &version_encoded); | 1711 leveldb_transaction->Put(exists_entry_key, &version_encoded); |
| 1246 | 1712 |
| 1247 std::string key_encoded; | 1713 std::string key_encoded; |
| 1248 EncodeIDBKey(key, &key_encoded); | 1714 EncodeIDBKey(key, &key_encoded); |
| 1249 record_identifier->Reset(key_encoded, version); | 1715 record_identifier->Reset(key_encoded, version); |
| 1250 return true; | 1716 return true; |
| 1251 } | 1717 } |
| 1252 | 1718 |
| 1253 bool IndexedDBBackingStore::ClearObjectStore( | 1719 bool IndexedDBBackingStore::ClearObjectStore( |
| 1254 IndexedDBBackingStore::Transaction* transaction, | 1720 IndexedDBBackingStore::Transaction* transaction, |
| 1255 int64 database_id, | 1721 int64 database_id, |
| 1256 int64 object_store_id) { | 1722 int64 object_store_id) { |
| 1257 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); | 1723 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); |
| 1258 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1724 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
| 1259 return false; | 1725 return false; |
| 1260 const std::string start_key = | 1726 const std::string start_key = |
| 1261 KeyPrefix(database_id, object_store_id).Encode(); | 1727 KeyPrefix(database_id, object_store_id).Encode(); |
| 1262 const std::string stop_key = | 1728 const std::string stop_key = |
| 1263 KeyPrefix(database_id, object_store_id + 1).Encode(); | 1729 KeyPrefix(database_id, object_store_id + 1).Encode(); |
| 1264 | 1730 |
| 1265 DeleteRange(transaction->transaction(), start_key, stop_key); | 1731 DeleteRangeByKeys(transaction->transaction(), start_key, stop_key); |
| 1732 DeleteBlobsInObjectStore(transaction, database_id, object_store_id); | |
| 1266 return true; | 1733 return true; |
| 1267 } | 1734 } |
| 1268 | 1735 |
| 1269 bool IndexedDBBackingStore::DeleteRecord( | 1736 bool IndexedDBBackingStore::DeleteRecord( |
| 1270 IndexedDBBackingStore::Transaction* transaction, | 1737 IndexedDBBackingStore::Transaction* transaction, |
| 1271 int64 database_id, | 1738 int64 database_id, |
| 1272 int64 object_store_id, | 1739 int64 object_store_id, |
| 1273 const RecordIdentifier& record_identifier) { | 1740 const RecordIdentifier& record_identifier) { |
| 1274 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); | 1741 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); |
| 1275 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1742 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
| 1276 return false; | 1743 return false; |
| 1277 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1744 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 1278 | 1745 |
| 1279 const std::string object_store_data_key = ObjectStoreDataKey::Encode( | 1746 const std::string object_store_data_key = ObjectStoreDataKey::Encode( |
| 1280 database_id, object_store_id, record_identifier.primary_key()); | 1747 database_id, object_store_id, record_identifier.primary_key()); |
| 1281 leveldb_transaction->Remove(object_store_data_key); | 1748 leveldb_transaction->Remove(object_store_data_key); |
| 1749 transaction->PutBlobInfo(database_id, object_store_id, object_store_data_key, | |
| 1750 NULL, NULL); | |
| 1282 | 1751 |
| 1283 const std::string exists_entry_key = ExistsEntryKey::Encode( | 1752 const std::string exists_entry_key = ExistsEntryKey::Encode( |
| 1284 database_id, object_store_id, record_identifier.primary_key()); | 1753 database_id, object_store_id, record_identifier.primary_key()); |
| 1285 leveldb_transaction->Remove(exists_entry_key); | 1754 leveldb_transaction->Remove(exists_entry_key); |
| 1286 return true; | 1755 return true; |
| 1287 } | 1756 } |
| 1288 | 1757 |
| 1758 bool IndexedDBBackingStore::DeleteRange( | |
| 1759 IndexedDBBackingStore::Transaction* transaction, | |
| 1760 int64 database_id, | |
| 1761 int64 object_store_id, | |
| 1762 const IndexedDBKeyRange& key_range) { | |
| 1763 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = | |
| 1764 OpenObjectStoreCursor(transaction, database_id, object_store_id, | |
| 1765 key_range, indexed_db::CURSOR_NEXT); | |
| 1766 // TODO(ericu): This does a PutBlobInfo for every record, even if it doesn't | |
| 1767 // have any blobs associated with it. We could skip that, and just scan | |
| 1768 // through the blob table to see which ones we need to remove. That might | |
| 1769 // take a little more time here, but would also potentially allocate a lot | |
| 1770 // fewer BlobChangeRecords, shrink the eventual WriteBatch, and do a lot fewer | |
| 1771 // seeks in CollectBlobFilesToRemove. | |
| 1772 if (backing_store_cursor) { | |
| 1773 do { | |
| 1774 if (!DeleteRecord( | |
| 1775 transaction, database_id, object_store_id, | |
| 1776 backing_store_cursor->record_identifier())) | |
| 1777 return false; | |
| 1778 } while (backing_store_cursor->Continue()); | |
| 1779 } | |
| 1780 return true; | |
| 1781 } | |
| 1782 | |
| 1289 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( | 1783 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( |
| 1290 IndexedDBBackingStore::Transaction* transaction, | 1784 IndexedDBBackingStore::Transaction* transaction, |
| 1291 int64 database_id, | 1785 int64 database_id, |
| 1292 int64 object_store_id, | 1786 int64 object_store_id, |
| 1293 int64* key_generator_current_number) { | 1787 int64* key_generator_current_number) { |
| 1294 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1788 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
| 1295 return false; | 1789 return false; |
| 1296 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1790 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 1297 | 1791 |
| 1298 const std::string key_generator_current_number_key = | 1792 const std::string key_generator_current_number_key = |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1414 StringPiece slice(data); | 1908 StringPiece slice(data); |
| 1415 if (!DecodeVarInt(&slice, &version)) | 1909 if (!DecodeVarInt(&slice, &version)) |
| 1416 return false; | 1910 return false; |
| 1417 | 1911 |
| 1418 std::string encoded_key; | 1912 std::string encoded_key; |
| 1419 EncodeIDBKey(key, &encoded_key); | 1913 EncodeIDBKey(key, &encoded_key); |
| 1420 found_record_identifier->Reset(encoded_key, version); | 1914 found_record_identifier->Reset(encoded_key, version); |
| 1421 return true; | 1915 return true; |
| 1422 } | 1916 } |
| 1423 | 1917 |
| 1918 class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl : public | |
| 1919 IndexedDBBackingStore::Transaction::ChainedBlobWriter { | |
| 1920 public: | |
| 1921 typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec | |
| 1922 WriteDescriptorVec; | |
| 1923 ChainedBlobWriterImpl( | |
| 1924 int64 database_id, | |
| 1925 IndexedDBBackingStore* backingStore, | |
| 1926 WriteDescriptorVec& blobs, | |
| 1927 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback) | |
| 1928 : waiting_for_callback_(false), | |
| 1929 database_id_(database_id), | |
| 1930 backing_store_(backingStore), | |
| 1931 callback_(callback), | |
| 1932 aborted_(false) { | |
| 1933 blobs_.swap(blobs); | |
| 1934 iter_ = blobs_.begin(); | |
| 1935 WriteNextFile(); | |
| 1936 } | |
| 1937 | |
| 1938 void set_delegate(scoped_ptr<FileWriterDelegate> delegate) { | |
| 1939 delegate_.reset(delegate.release()); | |
| 1940 } | |
| 1941 | |
| 1942 void ReportWriteCompletion(bool succeeded, int64 bytes_written) { | |
| 1943 // TODO(ericu): Check bytes_written against the blob's snapshot value. | |
| 1944 DCHECK(waiting_for_callback_); | |
| 1945 DCHECK(!succeeded || bytes_written >= 0); | |
| 1946 waiting_for_callback_ = false; | |
| 1947 content::BrowserThread::DeleteSoon( | |
| 1948 content::BrowserThread::IO, FROM_HERE, | |
| 1949 delegate_.release()); | |
| 1950 if (aborted_) { | |
| 1951 self_ref_ = NULL; | |
| 1952 return; | |
| 1953 } | |
| 1954 if (succeeded) | |
| 1955 WriteNextFile(); | |
| 1956 else | |
| 1957 callback_->didFail(); | |
| 1958 } | |
| 1959 | |
| 1960 void Abort() { | |
| 1961 if (!waiting_for_callback_) | |
| 1962 return; | |
| 1963 self_ref_ = this; | |
| 1964 aborted_ = true; | |
| 1965 } | |
| 1966 | |
| 1967 private: | |
| 1968 void WriteNextFile() { | |
| 1969 DCHECK(!waiting_for_callback_); | |
| 1970 DCHECK(!aborted_); | |
| 1971 if (iter_ == blobs_.end()) { | |
| 1972 DCHECK(!self_ref_); | |
| 1973 callback_->didSucceed(); | |
| 1974 return; | |
| 1975 } else { | |
| 1976 if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { | |
| 1977 callback_->didFail(); | |
| 1978 return; | |
| 1979 } | |
| 1980 waiting_for_callback_ = true; | |
| 1981 ++iter_; | |
| 1982 } | |
| 1983 } | |
| 1984 | |
| 1985 bool waiting_for_callback_; | |
| 1986 scoped_refptr<ChainedBlobWriterImpl> self_ref_; | |
| 1987 WriteDescriptorVec blobs_; | |
| 1988 WriteDescriptorVec::const_iterator iter_; | |
| 1989 int64 database_id_; | |
| 1990 IndexedDBBackingStore* backing_store_; | |
| 1991 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; | |
| 1992 scoped_ptr<FileWriterDelegate> delegate_; | |
| 1993 bool aborted_; | |
| 1994 }; | |
| 1995 | |
| 1996 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback, | |
| 1997 public base::RefCounted<LocalWriteClosure> { | |
| 1998 public: | |
| 1999 LocalWriteClosure( | |
| 2000 IndexedDBBackingStore::Transaction::ChainedBlobWriter* | |
| 2001 chained_blob_writer_, | |
| 2002 base::TaskRunner* task_runner) | |
| 2003 : chained_blob_writer_(chained_blob_writer_), | |
| 2004 task_runner_(task_runner), | |
| 2005 bytes_written_(-1) { | |
| 2006 } | |
| 2007 | |
| 2008 void Run( | |
| 2009 base::PlatformFileError rv, | |
| 2010 int64 bytes, | |
| 2011 FileWriterDelegate::WriteProgressStatus write_status) { | |
| 2012 if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING) | |
| 2013 return; // We don't care about progress events. | |
| 2014 if (rv == base::PLATFORM_FILE_OK) { | |
| 2015 DCHECK(bytes >= 0); | |
| 2016 DCHECK(write_status == FileWriterDelegate::SUCCESS_COMPLETED); | |
| 2017 bytes_written_ = bytes; | |
| 2018 } else { | |
| 2019 DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED || | |
| 2020 write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED); | |
| 2021 } | |
| 2022 task_runner_->PostTask( | |
| 2023 FROM_HERE, | |
| 2024 base::Bind( | |
| 2025 &LocalWriteClosure::callBlobCallbackOnIDBTaskRunner, this, | |
| 2026 write_status == FileWriterDelegate::SUCCESS_COMPLETED)); | |
| 2027 } | |
| 2028 | |
| 2029 void writeBlobToFileOnIOThread( | |
| 2030 const FilePath& file_path, const GURL& blob_url, | |
| 2031 net::URLRequestContext* request_context) { | |
| 2032 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 2033 scoped_ptr<fileapi::FileStreamWriter> writer( | |
| 2034 fileapi::FileStreamWriter::CreateForLocalFile( | |
| 2035 task_runner_, file_path, 0, false)); | |
| 2036 scoped_ptr<FileWriterDelegate> delegate( | |
| 2037 new FileWriterDelegate(writer.Pass())); | |
| 2038 | |
| 2039 DCHECK(blob_url.is_valid()); | |
| 2040 scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest( | |
| 2041 blob_url, net::DEFAULT_PRIORITY, delegate.get())); | |
| 2042 | |
| 2043 delegate->Start(blob_request.Pass(), | |
| 2044 base::Bind(&LocalWriteClosure::Run, this)); | |
| 2045 chained_blob_writer_->set_delegate(delegate.Pass()); | |
| 2046 } | |
| 2047 | |
| 2048 private: | |
| 2049 void callBlobCallbackOnIDBTaskRunner(bool succeeded) { | |
| 2050 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
| 2051 chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_); | |
| 2052 } | |
| 2053 | |
| 2054 IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_; | |
| 2055 base::TaskRunner* task_runner_; | |
| 2056 int64 bytes_written_; | |
| 2057 }; | |
| 2058 | |
| 2059 bool IndexedDBBackingStore::WriteBlobFile( | |
| 2060 int64 database_id, | |
| 2061 const Transaction::WriteDescriptor& descriptor, | |
| 2062 Transaction::ChainedBlobWriter* chained_blob_writer) { | |
| 2063 | |
| 2064 if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) | |
| 2065 return false; | |
| 2066 | |
| 2067 FilePath path = GetIDBBlobFileName(database_id, descriptor.key()); | |
| 2068 | |
| 2069 if (descriptor.is_file()) { | |
| 2070 DCHECK(!descriptor.file_path().empty()); | |
| 2071 if (!base::CopyFile(descriptor.file_path(), path)) | |
| 2072 return false; | |
| 2073 | |
| 2074 base::PlatformFileInfo info; | |
| 2075 if (file_util::GetFileInfo(descriptor.file_path(), &info)) { | |
| 2076 // TODO(ericu): Validate the snapshot date here. Expand WriteDescriptor | |
| 2077 // to include snapshot date and file size, and check both. | |
| 2078 if (!file_util::TouchFile(path, info.last_accessed, info.last_modified)) | |
| 2079 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
| 2080 } else { | |
| 2081 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
| 2082 } | |
| 2083 | |
| 2084 task_runner_->PostTask( | |
| 2085 FROM_HERE, | |
| 2086 base::Bind( | |
| 2087 &Transaction::ChainedBlobWriter::ReportWriteCompletion, | |
| 2088 chained_blob_writer, true, info.size)); | |
| 2089 } else { | |
| 2090 DCHECK(descriptor.url().is_valid()); | |
| 2091 scoped_refptr<LocalWriteClosure> write_closure( | |
| 2092 new LocalWriteClosure(chained_blob_writer, task_runner_)); | |
| 2093 content::BrowserThread::PostTask( | |
| 2094 content::BrowserThread::IO, FROM_HERE, | |
| 2095 base::Bind( | |
| 2096 &LocalWriteClosure::writeBlobToFileOnIOThread, write_closure.get(), | |
| 2097 path, descriptor.url(), request_context_)); | |
| 2098 } | |
| 2099 return true; | |
| 2100 } | |
| 2101 | |
| 2102 void IndexedDBBackingStore::ReportBlobUnused( | |
| 2103 int64 database_id, | |
| 2104 int64 blob_key) { | |
| 2105 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
| 2106 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
| 2107 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
| 2108 scoped_refptr<LevelDBTransaction> transaction = | |
| 2109 new LevelDBTransaction(db_.get()); | |
| 2110 | |
| 2111 std::string live_blob_key = LiveBlobJournalKey::Encode(); | |
| 2112 IndexedDBBackingStore::Transaction::BlobJournalType live_blob_journal; | |
| 2113 if (!GetBlobJournal(live_blob_key, transaction.get(), live_blob_journal)) | |
| 2114 return; | |
| 2115 DCHECK(live_blob_journal.size()); | |
| 2116 | |
| 2117 std::string primary_key = BlobJournalKey::Encode(); | |
| 2118 IndexedDBBackingStore::Transaction::BlobJournalType primary_journal; | |
| 2119 if (!GetBlobJournal(primary_key, transaction.get(), primary_journal)) | |
| 2120 return; | |
| 2121 | |
| 2122 IndexedDBBackingStore::Transaction::BlobJournalType::iterator journal_iter; | |
| 2123 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to | |
| 2124 // remove all entries with database_id from the live_blob journal and add only | |
| 2125 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) | |
| 2126 // and we hit kAllBlobsKey for the right database_id in the journal, we leave | |
| 2127 // the kAllBlobsKey entry in the live_blob journal but add the specific blob | |
| 2128 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a | |
| 2129 // matching (database_id, blob_key) tuple, we should move it to the primary | |
| 2130 // journal. | |
| 2131 IndexedDBBackingStore::Transaction::BlobJournalType new_live_blob_journal; | |
| 2132 for (journal_iter = live_blob_journal.begin(); | |
| 2133 journal_iter != live_blob_journal.end(); ++journal_iter) { | |
| 2134 int64 current_database_id = journal_iter->first; | |
| 2135 int64 current_blob_key = journal_iter->second; | |
| 2136 bool current_all_blobs = | |
| 2137 current_blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
| 2138 DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) || | |
| 2139 current_all_blobs); | |
| 2140 if (current_database_id == database_id && (all_blobs || | |
| 2141 current_all_blobs || blob_key == current_blob_key)) { | |
| 2142 if (!all_blobs) { | |
| 2143 primary_journal.push_back( | |
| 2144 std::make_pair(database_id, current_blob_key)); | |
| 2145 if (current_all_blobs) | |
| 2146 new_live_blob_journal.push_back(*journal_iter); | |
| 2147 new_live_blob_journal.insert(new_live_blob_journal.end(), | |
| 2148 ++journal_iter, live_blob_journal.end()); // All the rest. | |
| 2149 break; | |
| 2150 } | |
| 2151 } else { | |
| 2152 new_live_blob_journal.push_back(*journal_iter); | |
| 2153 } | |
| 2154 } | |
| 2155 if (all_blobs) { | |
| 2156 primary_journal.push_back(std::make_pair( | |
| 2157 database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 2158 } | |
| 2159 UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal); | |
| 2160 UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal); | |
| 2161 transaction->Commit(); | |
| 2162 // We could just do the deletions/cleaning here, but if there are a lot of | |
| 2163 // blobs about to be garbage collected, it'd be better to wait and do them all | |
| 2164 // at once. | |
| 2165 StartJournalCleaningTimer(); | |
| 2166 } | |
| 2167 | |
| 2168 void IndexedDBBackingStore::StartJournalCleaningTimer() { | |
| 2169 journal_cleaning_timer_.Start( | |
| 2170 FROM_HERE, base::TimeDelta::FromSeconds(5), this, | |
|
jsbell
2013/12/18 23:04:40
Need to rationalize this time with the "lazy close
ericu
2013/12/19 05:19:11
Yeah, this is kind of arbitrary here. Also, if th
| |
| 2171 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); | |
| 2172 } | |
| 2173 | |
| 2174 // This assumes a file path of dbId/3rd-byte-of-counter/counter. | |
| 2175 FilePath IndexedDBBackingStore::GetIDBBlobFileName( | |
| 2176 int64 database_id, int64 key) { | |
| 2177 FilePath path = GetIDBBlobDirectoryNameForKey(blob_path_, database_id, key); | |
| 2178 path = path.AppendASCII(base::StringPrintf("%lx", key)); | |
| 2179 return path; | |
| 2180 } | |
| 2181 | |
| 1424 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 2182 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
| 1425 const std::string& stop_key, | 2183 const std::string& stop_key, |
| 1426 int64 index_id, | 2184 int64 index_id, |
| 1427 unsigned char meta_data_type) { | 2185 unsigned char meta_data_type) { |
| 1428 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 2186 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
| 1429 return false; | 2187 return false; |
| 1430 | 2188 |
| 1431 StringPiece slice(it->Key()); | 2189 StringPiece slice(it->Key()); |
| 1432 IndexMetaDataKey meta_data_key; | 2190 IndexMetaDataKey meta_data_key; |
| 1433 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); | 2191 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1516 | 2274 |
| 1517 it->Next(); | 2275 it->Next(); |
| 1518 } | 2276 } |
| 1519 | 2277 |
| 1520 (*indexes)[index_id] = IndexedDBIndexMetadata( | 2278 (*indexes)[index_id] = IndexedDBIndexMetadata( |
| 1521 index_name, index_id, key_path, index_unique, index_multi_entry); | 2279 index_name, index_id, key_path, index_unique, index_multi_entry); |
| 1522 } | 2280 } |
| 1523 return true; | 2281 return true; |
| 1524 } | 2282 } |
| 1525 | 2283 |
| 2284 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { | |
| 2285 FilePath fileName = GetIDBBlobFileName(database_id, key); | |
| 2286 return base::DeleteFile(fileName, false); | |
| 2287 } | |
| 2288 | |
| 2289 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | |
| 2290 FilePath dirName = GetIDBBlobDirectoryName(blob_path_, database_id); | |
| 2291 return base::DeleteFile(dirName, true); | |
| 2292 } | |
| 2293 | |
| 2294 bool IndexedDBBackingStore::CleanUpBlobJournal( | |
| 2295 const std::string& level_db_key) { | |
| 2296 scoped_refptr<LevelDBTransaction> journal_transaction = | |
| 2297 new LevelDBTransaction(db_.get()); | |
| 2298 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
| 2299 if (!GetBlobJournal(level_db_key, journal_transaction.get(), | |
| 2300 journal)) { | |
| 2301 return false; | |
| 2302 } | |
| 2303 if (!journal.size()) { | |
| 2304 return true; | |
| 2305 } | |
| 2306 if (journal.size()) { | |
|
jsbell
2013/12/18 23:04:40
Redundant with above check.
ericu
2013/12/19 05:19:11
Done.
| |
| 2307 IndexedDBBackingStore::Transaction::BlobJournalType::iterator journal_iter; | |
| 2308 for (journal_iter = journal.begin(); journal_iter != journal.end(); | |
| 2309 ++journal_iter) { | |
| 2310 int64 database_id = journal_iter->first; | |
| 2311 int64 blob_key = journal_iter->second; | |
| 2312 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
| 2313 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { | |
| 2314 RemoveBlobDirectory(database_id); | |
| 2315 } else { | |
| 2316 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
| 2317 RemoveBlobFile(database_id, blob_key); | |
| 2318 } | |
| 2319 } | |
| 2320 } | |
| 2321 ClearBlobJournal(journal_transaction.get(), level_db_key); | |
| 2322 return journal_transaction->Commit(); | |
| 2323 } | |
| 2324 | |
| 2325 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { | |
| 2326 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 2327 } | |
| 2328 | |
| 1526 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, | 2329 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, |
| 1527 int64 database_id, | 2330 int64 database_id, |
| 1528 int64 object_store_id, | 2331 int64 object_store_id, |
| 1529 int64 index_id) { | 2332 int64 index_id) { |
| 1530 int64 max_index_id = -1; | 2333 int64 max_index_id = -1; |
| 1531 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2334 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
| 1532 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2335 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
| 1533 bool found = false; | 2336 bool found = false; |
| 1534 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); | 2337 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); |
| 1535 if (!ok) { | 2338 if (!ok) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1588 int64 index_id) { | 2391 int64 index_id) { |
| 1589 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); | 2392 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); |
| 1590 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) | 2393 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
| 1591 return false; | 2394 return false; |
| 1592 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 2395 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 1593 | 2396 |
| 1594 const std::string index_meta_data_start = | 2397 const std::string index_meta_data_start = |
| 1595 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); | 2398 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); |
| 1596 const std::string index_meta_data_end = | 2399 const std::string index_meta_data_end = |
| 1597 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 2400 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); |
| 1598 DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end); | 2401 DeleteRangeByKeys(leveldb_transaction, index_meta_data_start, |
| 2402 index_meta_data_end); | |
| 1599 | 2403 |
| 1600 const std::string index_data_start = | 2404 const std::string index_data_start = |
| 1601 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); | 2405 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); |
| 1602 const std::string index_data_end = | 2406 const std::string index_data_end = |
| 1603 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 2407 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); |
| 1604 DeleteRange(leveldb_transaction, index_data_start, index_data_end); | 2408 DeleteRangeByKeys(leveldb_transaction, index_data_start, index_data_end); |
| 1605 return true; | 2409 return true; |
| 1606 } | 2410 } |
| 1607 | 2411 |
| 1608 bool IndexedDBBackingStore::PutIndexDataForRecord( | 2412 bool IndexedDBBackingStore::PutIndexDataForRecord( |
| 1609 IndexedDBBackingStore::Transaction* transaction, | 2413 IndexedDBBackingStore::Transaction* transaction, |
| 1610 int64 database_id, | 2414 int64 database_id, |
| 1611 int64 object_store_id, | 2415 int64 object_store_id, |
| 1612 int64 index_id, | 2416 int64 index_id, |
| 1613 const IndexedDBKey& key, | 2417 const IndexedDBKey& key, |
| 1614 const RecordIdentifier& record_identifier) { | 2418 const RecordIdentifier& record_identifier) { |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1811 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); | 2615 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); |
| 1812 return false; | 2616 return false; |
| 1813 } | 2617 } |
| 1814 | 2618 |
| 1815 StringPiece slice(found_encoded_primary_key); | 2619 StringPiece slice(found_encoded_primary_key); |
| 1816 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); | 2620 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); |
| 1817 } | 2621 } |
| 1818 | 2622 |
| 1819 IndexedDBBackingStore::Cursor::Cursor( | 2623 IndexedDBBackingStore::Cursor::Cursor( |
| 1820 const IndexedDBBackingStore::Cursor* other) | 2624 const IndexedDBBackingStore::Cursor* other) |
| 1821 : transaction_(other->transaction_), | 2625 : backing_store_(other->backing_store_), |
| 2626 transaction_(other->transaction_), | |
| 2627 database_id_(other->database_id_), | |
| 1822 cursor_options_(other->cursor_options_), | 2628 cursor_options_(other->cursor_options_), |
| 1823 current_key_(new IndexedDBKey(*other->current_key_)) { | 2629 current_key_(new IndexedDBKey(*other->current_key_)) { |
| 1824 if (other->iterator_) { | 2630 if (other->iterator_) { |
| 1825 iterator_ = transaction_->CreateIterator(); | 2631 iterator_ = transaction_->CreateIterator(); |
| 1826 | 2632 |
| 1827 if (other->iterator_->IsValid()) { | 2633 if (other->iterator_->IsValid()) { |
| 1828 iterator_->Seek(other->iterator_->Key()); | 2634 iterator_->Seek(other->iterator_->Key()); |
| 1829 DCHECK(iterator_->IsValid()); | 2635 DCHECK(iterator_->IsValid()); |
| 1830 } | 2636 } |
| 1831 } | 2637 } |
| 1832 } | 2638 } |
| 1833 | 2639 |
| 1834 IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction, | 2640 IndexedDBBackingStore::Cursor::Cursor( |
| 1835 const CursorOptions& cursor_options) | 2641 scoped_refptr<IndexedDBBackingStore> backing_store, |
|
jsbell
2013/12/18 23:04:40
This is an interesting new arc in the ownership di
ericu
2013/12/19 05:19:11
OK.
| |
| 1836 : transaction_(transaction), cursor_options_(cursor_options) {} | 2642 LevelDBTransaction* transaction, |
| 2643 int64 database_id, | |
| 2644 const CursorOptions& cursor_options) | |
| 2645 : backing_store_(backing_store), | |
| 2646 transaction_(transaction), | |
| 2647 database_id_(database_id), | |
| 2648 cursor_options_(cursor_options) { | |
| 2649 } | |
| 1837 IndexedDBBackingStore::Cursor::~Cursor() {} | 2650 IndexedDBBackingStore::Cursor::~Cursor() {} |
| 1838 | 2651 |
| 1839 bool IndexedDBBackingStore::Cursor::FirstSeek() { | 2652 bool IndexedDBBackingStore::Cursor::FirstSeek() { |
| 1840 iterator_ = transaction_->CreateIterator(); | 2653 iterator_ = transaction_->CreateIterator(); |
| 1841 if (cursor_options_.forward) | 2654 if (cursor_options_.forward) |
| 1842 iterator_->Seek(cursor_options_.low_key); | 2655 iterator_->Seek(cursor_options_.low_key); |
| 1843 else | 2656 else |
| 1844 iterator_->Seek(cursor_options_.high_key); | 2657 iterator_->Seek(cursor_options_.high_key); |
| 1845 | 2658 |
| 1846 return Continue(0, READY); | 2659 return Continue(0, READY); |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2006 } | 2819 } |
| 2007 | 2820 |
| 2008 const IndexedDBBackingStore::RecordIdentifier& | 2821 const IndexedDBBackingStore::RecordIdentifier& |
| 2009 IndexedDBBackingStore::Cursor::record_identifier() const { | 2822 IndexedDBBackingStore::Cursor::record_identifier() const { |
| 2010 return record_identifier_; | 2823 return record_identifier_; |
| 2011 } | 2824 } |
| 2012 | 2825 |
| 2013 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 2826 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { |
| 2014 public: | 2827 public: |
| 2015 ObjectStoreKeyCursorImpl( | 2828 ObjectStoreKeyCursorImpl( |
| 2829 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2016 LevelDBTransaction* transaction, | 2830 LevelDBTransaction* transaction, |
| 2831 int64 database_id, | |
| 2017 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2832 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
| 2018 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2833 : IndexedDBBackingStore::Cursor( |
| 2834 backing_store, transaction, database_id, cursor_options) {} | |
| 2019 | 2835 |
| 2020 virtual Cursor* Clone() OVERRIDE { | 2836 virtual Cursor* Clone() OVERRIDE { |
| 2021 return new ObjectStoreKeyCursorImpl(this); | 2837 return new ObjectStoreKeyCursorImpl(this); |
| 2022 } | 2838 } |
| 2023 | 2839 |
| 2024 // IndexedDBBackingStore::Cursor | 2840 // IndexedDBBackingStore::Cursor |
| 2025 virtual std::string* Value() OVERRIDE { | 2841 virtual IndexedDBValue* Value() OVERRIDE { |
| 2026 NOTREACHED(); | 2842 NOTREACHED(); |
| 2027 return NULL; | 2843 return NULL; |
| 2028 } | 2844 } |
| 2029 virtual bool LoadCurrentRow() OVERRIDE; | 2845 virtual bool LoadCurrentRow() OVERRIDE; |
| 2030 | 2846 |
| 2031 protected: | 2847 protected: |
| 2032 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2848 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
| 2033 return ObjectStoreDataKey::Encode( | 2849 return ObjectStoreDataKey::Encode( |
| 2034 cursor_options_.database_id, cursor_options_.object_store_id, key); | 2850 cursor_options_.database_id, cursor_options_.object_store_id, key); |
| 2035 } | 2851 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 2065 std::string encoded_key; | 2881 std::string encoded_key; |
| 2066 EncodeIDBKey(*current_key_, &encoded_key); | 2882 EncodeIDBKey(*current_key_, &encoded_key); |
| 2067 record_identifier_.Reset(encoded_key, version); | 2883 record_identifier_.Reset(encoded_key, version); |
| 2068 | 2884 |
| 2069 return true; | 2885 return true; |
| 2070 } | 2886 } |
| 2071 | 2887 |
| 2072 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { | 2888 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { |
| 2073 public: | 2889 public: |
| 2074 ObjectStoreCursorImpl( | 2890 ObjectStoreCursorImpl( |
| 2891 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2075 LevelDBTransaction* transaction, | 2892 LevelDBTransaction* transaction, |
| 2893 int64 database_id, | |
| 2076 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2894 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
| 2077 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2895 : IndexedDBBackingStore::Cursor( |
| 2896 backing_store, transaction, database_id, cursor_options) {} | |
| 2078 | 2897 |
| 2079 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } | 2898 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } |
| 2080 | 2899 |
| 2081 // IndexedDBBackingStore::Cursor | 2900 // IndexedDBBackingStore::Cursor |
| 2082 virtual std::string* Value() OVERRIDE { return ¤t_value_; } | 2901 virtual IndexedDBValue* Value() OVERRIDE { return ¤t_value_; } |
| 2083 virtual bool LoadCurrentRow() OVERRIDE; | 2902 virtual bool LoadCurrentRow() OVERRIDE; |
| 2084 | 2903 |
| 2085 protected: | 2904 protected: |
| 2086 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2905 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
| 2087 return ObjectStoreDataKey::Encode( | 2906 return ObjectStoreDataKey::Encode( |
| 2088 cursor_options_.database_id, cursor_options_.object_store_id, key); | 2907 cursor_options_.database_id, cursor_options_.object_store_id, key); |
| 2089 } | 2908 } |
| 2090 virtual std::string EncodeKey(const IndexedDBKey& key, | 2909 virtual std::string EncodeKey(const IndexedDBKey& key, |
| 2091 const IndexedDBKey& primary_key) OVERRIDE { | 2910 const IndexedDBKey& primary_key) OVERRIDE { |
| 2092 NOTREACHED(); | 2911 NOTREACHED(); |
| 2093 return std::string(); | 2912 return std::string(); |
| 2094 } | 2913 } |
| 2095 | 2914 |
| 2096 private: | 2915 private: |
| 2097 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) | 2916 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) |
| 2098 : IndexedDBBackingStore::Cursor(other), | 2917 : IndexedDBBackingStore::Cursor(other), |
| 2099 current_value_(other->current_value_) {} | 2918 current_value_(other->current_value_) {} |
| 2100 | 2919 |
| 2101 std::string current_value_; | 2920 IndexedDBValue current_value_; |
| 2102 }; | 2921 }; |
| 2103 | 2922 |
| 2104 bool ObjectStoreCursorImpl::LoadCurrentRow() { | 2923 bool ObjectStoreCursorImpl::LoadCurrentRow() { |
| 2105 StringPiece slice(iterator_->Key()); | 2924 StringPiece key_slice(iterator_->Key()); |
| 2106 ObjectStoreDataKey object_store_data_key; | 2925 ObjectStoreDataKey object_store_data_key; |
| 2107 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { | 2926 if (!ObjectStoreDataKey::Decode(&key_slice, &object_store_data_key)) { |
| 2108 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 2927 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
| 2109 return false; | 2928 return false; |
| 2110 } | 2929 } |
| 2111 | 2930 |
| 2112 current_key_ = object_store_data_key.user_key(); | 2931 current_key_ = object_store_data_key.user_key(); |
| 2113 | 2932 |
| 2114 int64 version; | 2933 int64 version; |
| 2115 slice = StringPiece(iterator_->Value()); | 2934 StringPiece value_slice = StringPiece(iterator_->Value()); |
| 2116 if (!DecodeVarInt(&slice, &version)) { | 2935 if (!DecodeVarInt(&value_slice, &version)) { |
| 2117 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 2936 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
| 2118 return false; | 2937 return false; |
| 2119 } | 2938 } |
| 2120 | 2939 |
| 2121 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. | 2940 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. |
| 2122 std::string encoded_key; | 2941 std::string encoded_key; |
| 2123 EncodeIDBKey(*current_key_, &encoded_key); | 2942 EncodeIDBKey(*current_key_, &encoded_key); |
| 2124 record_identifier_.Reset(encoded_key, version); | 2943 record_identifier_.Reset(encoded_key, version); |
| 2125 | 2944 |
| 2126 current_value_ = slice.as_string(); | 2945 if (!GetBlobInfoForRecord(backing_store_, transaction_, database_id_, |
| 2946 iterator_->Key().as_string(), ¤t_value_)) { | |
| 2947 return false; | |
| 2948 } | |
| 2949 current_value_.bits = value_slice.as_string(); | |
| 2127 return true; | 2950 return true; |
| 2128 } | 2951 } |
| 2129 | 2952 |
| 2130 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 2953 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { |
| 2131 public: | 2954 public: |
| 2132 IndexKeyCursorImpl( | 2955 IndexKeyCursorImpl( |
| 2956 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2133 LevelDBTransaction* transaction, | 2957 LevelDBTransaction* transaction, |
| 2958 int64 database_id, | |
| 2134 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2959 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
| 2135 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2960 : IndexedDBBackingStore::Cursor( |
| 2961 backing_store, transaction, database_id, cursor_options) {} | |
| 2136 | 2962 |
| 2137 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } | 2963 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } |
| 2138 | 2964 |
| 2139 // IndexedDBBackingStore::Cursor | 2965 // IndexedDBBackingStore::Cursor |
| 2140 virtual std::string* Value() OVERRIDE { | 2966 virtual IndexedDBValue* Value() OVERRIDE { |
| 2141 NOTREACHED(); | 2967 NOTREACHED(); |
| 2142 return NULL; | 2968 return NULL; |
| 2143 } | 2969 } |
| 2144 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 2970 virtual const IndexedDBKey& primary_key() const OVERRIDE { |
| 2145 return *primary_key_; | 2971 return *primary_key_; |
| 2146 } | 2972 } |
| 2147 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() | 2973 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() |
| 2148 const { | 2974 const OVERRIDE { |
| 2149 NOTREACHED(); | 2975 NOTREACHED(); |
| 2150 return record_identifier_; | 2976 return record_identifier_; |
| 2151 } | 2977 } |
| 2152 virtual bool LoadCurrentRow() OVERRIDE; | 2978 virtual bool LoadCurrentRow() OVERRIDE; |
| 2153 | 2979 |
| 2154 protected: | 2980 protected: |
| 2155 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2981 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
| 2156 return IndexDataKey::Encode(cursor_options_.database_id, | 2982 return IndexDataKey::Encode(cursor_options_.database_id, |
| 2157 cursor_options_.object_store_id, | 2983 cursor_options_.object_store_id, |
| 2158 cursor_options_.index_id, | 2984 cursor_options_.index_id, |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2230 transaction_->Remove(iterator_->Key()); | 3056 transaction_->Remove(iterator_->Key()); |
| 2231 return false; | 3057 return false; |
| 2232 } | 3058 } |
| 2233 | 3059 |
| 2234 return true; | 3060 return true; |
| 2235 } | 3061 } |
| 2236 | 3062 |
| 2237 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { | 3063 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { |
| 2238 public: | 3064 public: |
| 2239 IndexCursorImpl( | 3065 IndexCursorImpl( |
| 3066 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2240 LevelDBTransaction* transaction, | 3067 LevelDBTransaction* transaction, |
| 3068 int64 database_id, | |
| 2241 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 3069 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
| 2242 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 3070 : IndexedDBBackingStore::Cursor( |
| 3071 backing_store, transaction, database_id, cursor_options) {} | |
| 2243 | 3072 |
| 2244 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } | 3073 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } |
| 2245 | 3074 |
| 2246 // IndexedDBBackingStore::Cursor | 3075 // IndexedDBBackingStore::Cursor |
| 2247 virtual std::string* Value() OVERRIDE { return ¤t_value_; } | 3076 virtual IndexedDBValue* Value() OVERRIDE { return ¤t_value_; } |
| 2248 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 3077 virtual const IndexedDBKey& primary_key() const OVERRIDE { |
| 2249 return *primary_key_; | 3078 return *primary_key_; |
| 2250 } | 3079 } |
| 2251 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() | 3080 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() |
| 2252 const { | 3081 const OVERRIDE { |
| 2253 NOTREACHED(); | 3082 NOTREACHED(); |
| 2254 return record_identifier_; | 3083 return record_identifier_; |
| 2255 } | 3084 } |
| 2256 virtual bool LoadCurrentRow() OVERRIDE; | 3085 virtual bool LoadCurrentRow() OVERRIDE; |
| 2257 | 3086 |
| 2258 protected: | 3087 protected: |
| 2259 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 3088 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
| 2260 return IndexDataKey::Encode(cursor_options_.database_id, | 3089 return IndexDataKey::Encode(cursor_options_.database_id, |
| 2261 cursor_options_.object_store_id, | 3090 cursor_options_.object_store_id, |
| 2262 cursor_options_.index_id, | 3091 cursor_options_.index_id, |
| 2263 key); | 3092 key); |
| 2264 } | 3093 } |
| 2265 virtual std::string EncodeKey(const IndexedDBKey& key, | 3094 virtual std::string EncodeKey(const IndexedDBKey& key, |
| 2266 const IndexedDBKey& primary_key) OVERRIDE { | 3095 const IndexedDBKey& primary_key) OVERRIDE { |
| 2267 return IndexDataKey::Encode(cursor_options_.database_id, | 3096 return IndexDataKey::Encode(cursor_options_.database_id, |
| 2268 cursor_options_.object_store_id, | 3097 cursor_options_.object_store_id, |
| 2269 cursor_options_.index_id, | 3098 cursor_options_.index_id, |
| 2270 key, | 3099 key, |
| 2271 primary_key); | 3100 primary_key); |
| 2272 } | 3101 } |
| 2273 | 3102 |
| 2274 private: | 3103 private: |
| 2275 explicit IndexCursorImpl(const IndexCursorImpl* other) | 3104 explicit IndexCursorImpl(const IndexCursorImpl* other) |
| 2276 : IndexedDBBackingStore::Cursor(other), | 3105 : IndexedDBBackingStore::Cursor(other), |
| 2277 primary_key_(new IndexedDBKey(*other->primary_key_)), | 3106 primary_key_(new IndexedDBKey(*other->primary_key_)), |
| 2278 current_value_(other->current_value_), | 3107 current_value_(other->current_value_), |
| 2279 primary_leveldb_key_(other->primary_leveldb_key_) {} | 3108 primary_leveldb_key_(other->primary_leveldb_key_) {} |
| 2280 | 3109 |
| 2281 scoped_ptr<IndexedDBKey> primary_key_; | 3110 scoped_ptr<IndexedDBKey> primary_key_; |
| 2282 std::string current_value_; | 3111 IndexedDBValue current_value_; |
| 2283 std::string primary_leveldb_key_; | 3112 std::string primary_leveldb_key_; |
| 2284 }; | 3113 }; |
| 2285 | 3114 |
| 2286 bool IndexCursorImpl::LoadCurrentRow() { | 3115 bool IndexCursorImpl::LoadCurrentRow() { |
| 2287 StringPiece slice(iterator_->Key()); | 3116 StringPiece slice(iterator_->Key()); |
| 2288 IndexDataKey index_data_key; | 3117 IndexDataKey index_data_key; |
| 2289 if (!IndexDataKey::Decode(&slice, &index_data_key)) { | 3118 if (!IndexDataKey::Decode(&slice, &index_data_key)) { |
| 2290 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3119 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
| 2291 return false; | 3120 return false; |
| 2292 } | 3121 } |
| 2293 | 3122 |
| 2294 current_key_ = index_data_key.user_key(); | 3123 current_key_ = index_data_key.user_key(); |
| 2295 DCHECK(current_key_); | 3124 DCHECK(current_key_); |
| 2296 | 3125 |
| 2297 slice = StringPiece(iterator_->Value()); | 3126 slice = StringPiece(iterator_->Value()); |
| 2298 int64 index_data_version; | 3127 int64 index_data_version; |
| 2299 if (!DecodeVarInt(&slice, &index_data_version)) { | 3128 if (!DecodeVarInt(&slice, &index_data_version)) { |
| 2300 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3129 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
| 2301 return false; | 3130 return false; |
| 2302 } | 3131 } |
| 2303 if (!DecodeIDBKey(&slice, &primary_key_)) { | 3132 if (!DecodeIDBKey(&slice, &primary_key_)) { |
| 2304 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3133 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
| 2305 return false; | 3134 return false; |
| 2306 } | 3135 } |
| 2307 | 3136 |
| 3137 DCHECK_EQ(index_data_key.DatabaseId(), database_id_); | |
| 2308 primary_leveldb_key_ = | 3138 primary_leveldb_key_ = |
| 2309 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), | 3139 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), |
| 2310 index_data_key.ObjectStoreId(), | 3140 index_data_key.ObjectStoreId(), |
| 2311 *primary_key_); | 3141 *primary_key_); |
| 2312 | 3142 |
| 2313 std::string result; | 3143 std::string result; |
| 2314 bool found = false; | 3144 bool found = false; |
| 2315 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); | 3145 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); |
| 2316 if (!ok) { | 3146 if (!ok) { |
| 2317 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3147 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 2331 if (!DecodeVarInt(&slice, &object_store_data_version)) { | 3161 if (!DecodeVarInt(&slice, &object_store_data_version)) { |
| 2332 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3162 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
| 2333 return false; | 3163 return false; |
| 2334 } | 3164 } |
| 2335 | 3165 |
| 2336 if (object_store_data_version != index_data_version) { | 3166 if (object_store_data_version != index_data_version) { |
| 2337 transaction_->Remove(iterator_->Key()); | 3167 transaction_->Remove(iterator_->Key()); |
| 2338 return false; | 3168 return false; |
| 2339 } | 3169 } |
| 2340 | 3170 |
| 2341 current_value_ = slice.as_string(); | 3171 current_value_.bits = slice.as_string(); |
| 2342 return true; | 3172 return GetBlobInfoForRecord(backing_store_, transaction_, database_id_, |
| 3173 primary_leveldb_key_, ¤t_value_); | |
| 2343 } | 3174 } |
| 2344 | 3175 |
| 2345 bool ObjectStoreCursorOptions( | 3176 bool ObjectStoreCursorOptions( |
| 2346 LevelDBTransaction* transaction, | 3177 LevelDBTransaction* transaction, |
| 2347 int64 database_id, | 3178 int64 database_id, |
| 2348 int64 object_store_id, | 3179 int64 object_store_id, |
| 2349 const IndexedDBKeyRange& range, | 3180 const IndexedDBKeyRange& range, |
| 2350 indexed_db::CursorDirection direction, | 3181 indexed_db::CursorDirection direction, |
| 2351 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { | 3182 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { |
| 2352 cursor_options->database_id = database_id; | 3183 cursor_options->database_id = database_id; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2489 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3320 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 2490 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3321 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
| 2491 if (!ObjectStoreCursorOptions(leveldb_transaction, | 3322 if (!ObjectStoreCursorOptions(leveldb_transaction, |
| 2492 database_id, | 3323 database_id, |
| 2493 object_store_id, | 3324 object_store_id, |
| 2494 range, | 3325 range, |
| 2495 direction, | 3326 direction, |
| 2496 &cursor_options)) | 3327 &cursor_options)) |
| 2497 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3328 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2498 scoped_ptr<ObjectStoreCursorImpl> cursor( | 3329 scoped_ptr<ObjectStoreCursorImpl> cursor( |
| 2499 new ObjectStoreCursorImpl(leveldb_transaction, cursor_options)); | 3330 new ObjectStoreCursorImpl( |
| 3331 this, leveldb_transaction, database_id, cursor_options)); | |
| 2500 if (!cursor->FirstSeek()) | 3332 if (!cursor->FirstSeek()) |
| 2501 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3333 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2502 | 3334 |
| 2503 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3335 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
| 2504 } | 3336 } |
| 2505 | 3337 |
| 2506 scoped_ptr<IndexedDBBackingStore::Cursor> | 3338 scoped_ptr<IndexedDBBackingStore::Cursor> |
| 2507 IndexedDBBackingStore::OpenObjectStoreKeyCursor( | 3339 IndexedDBBackingStore::OpenObjectStoreKeyCursor( |
| 2508 IndexedDBBackingStore::Transaction* transaction, | 3340 IndexedDBBackingStore::Transaction* transaction, |
| 2509 int64 database_id, | 3341 int64 database_id, |
| 2510 int64 object_store_id, | 3342 int64 object_store_id, |
| 2511 const IndexedDBKeyRange& range, | 3343 const IndexedDBKeyRange& range, |
| 2512 indexed_db::CursorDirection direction) { | 3344 indexed_db::CursorDirection direction) { |
| 2513 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); | 3345 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); |
| 2514 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3346 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 2515 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3347 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
| 2516 if (!ObjectStoreCursorOptions(leveldb_transaction, | 3348 if (!ObjectStoreCursorOptions(leveldb_transaction, |
| 2517 database_id, | 3349 database_id, |
| 2518 object_store_id, | 3350 object_store_id, |
| 2519 range, | 3351 range, |
| 2520 direction, | 3352 direction, |
| 2521 &cursor_options)) | 3353 &cursor_options)) |
| 2522 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3354 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2523 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( | 3355 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( |
| 2524 new ObjectStoreKeyCursorImpl(leveldb_transaction, cursor_options)); | 3356 new ObjectStoreKeyCursorImpl( |
| 3357 this, leveldb_transaction, database_id, cursor_options)); | |
| 2525 if (!cursor->FirstSeek()) | 3358 if (!cursor->FirstSeek()) |
| 2526 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3359 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2527 | 3360 |
| 2528 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3361 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
| 2529 } | 3362 } |
| 2530 | 3363 |
| 2531 scoped_ptr<IndexedDBBackingStore::Cursor> | 3364 scoped_ptr<IndexedDBBackingStore::Cursor> |
| 2532 IndexedDBBackingStore::OpenIndexKeyCursor( | 3365 IndexedDBBackingStore::OpenIndexKeyCursor( |
| 2533 IndexedDBBackingStore::Transaction* transaction, | 3366 IndexedDBBackingStore::Transaction* transaction, |
| 2534 int64 database_id, | 3367 int64 database_id, |
| 2535 int64 object_store_id, | 3368 int64 object_store_id, |
| 2536 int64 index_id, | 3369 int64 index_id, |
| 2537 const IndexedDBKeyRange& range, | 3370 const IndexedDBKeyRange& range, |
| 2538 indexed_db::CursorDirection direction) { | 3371 indexed_db::CursorDirection direction) { |
| 2539 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); | 3372 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); |
| 2540 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3373 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 2541 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3374 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
| 2542 if (!IndexCursorOptions(leveldb_transaction, | 3375 if (!IndexCursorOptions(leveldb_transaction, |
| 2543 database_id, | 3376 database_id, |
| 2544 object_store_id, | 3377 object_store_id, |
| 2545 index_id, | 3378 index_id, |
| 2546 range, | 3379 range, |
| 2547 direction, | 3380 direction, |
| 2548 &cursor_options)) | 3381 &cursor_options)) |
| 2549 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3382 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2550 scoped_ptr<IndexKeyCursorImpl> cursor( | 3383 scoped_ptr<IndexKeyCursorImpl> cursor( |
| 2551 new IndexKeyCursorImpl(leveldb_transaction, cursor_options)); | 3384 new IndexKeyCursorImpl( |
| 3385 this, leveldb_transaction, database_id, cursor_options)); | |
| 2552 if (!cursor->FirstSeek()) | 3386 if (!cursor->FirstSeek()) |
| 2553 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3387 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2554 | 3388 |
| 2555 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3389 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
| 2556 } | 3390 } |
| 2557 | 3391 |
| 2558 scoped_ptr<IndexedDBBackingStore::Cursor> | 3392 scoped_ptr<IndexedDBBackingStore::Cursor> |
| 2559 IndexedDBBackingStore::OpenIndexCursor( | 3393 IndexedDBBackingStore::OpenIndexCursor( |
| 2560 IndexedDBBackingStore::Transaction* transaction, | 3394 IndexedDBBackingStore::Transaction* transaction, |
| 2561 int64 database_id, | 3395 int64 database_id, |
| 2562 int64 object_store_id, | 3396 int64 object_store_id, |
| 2563 int64 index_id, | 3397 int64 index_id, |
| 2564 const IndexedDBKeyRange& range, | 3398 const IndexedDBKeyRange& range, |
| 2565 indexed_db::CursorDirection direction) { | 3399 indexed_db::CursorDirection direction) { |
| 2566 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); | 3400 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); |
| 2567 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3401 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
| 2568 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3402 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
| 2569 if (!IndexCursorOptions(leveldb_transaction, | 3403 if (!IndexCursorOptions(leveldb_transaction, |
| 2570 database_id, | 3404 database_id, |
| 2571 object_store_id, | 3405 object_store_id, |
| 2572 index_id, | 3406 index_id, |
| 2573 range, | 3407 range, |
| 2574 direction, | 3408 direction, |
| 2575 &cursor_options)) | 3409 &cursor_options)) |
| 2576 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3410 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2577 scoped_ptr<IndexCursorImpl> cursor( | 3411 scoped_ptr<IndexCursorImpl> cursor( |
| 2578 new IndexCursorImpl(leveldb_transaction, cursor_options)); | 3412 new IndexCursorImpl( |
| 3413 this, leveldb_transaction, database_id, cursor_options)); | |
| 2579 if (!cursor->FirstSeek()) | 3414 if (!cursor->FirstSeek()) |
| 2580 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3415 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 2581 | 3416 |
| 2582 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3417 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
| 2583 } | 3418 } |
| 2584 | 3419 |
| 2585 IndexedDBBackingStore::Transaction::Transaction( | 3420 IndexedDBBackingStore::Transaction::Transaction( |
| 2586 IndexedDBBackingStore* backing_store) | 3421 IndexedDBBackingStore* backing_store) |
| 2587 : backing_store_(backing_store) {} | 3422 : backing_store_(backing_store), |
| 3423 database_id_(-1) { | |
| 3424 } | |
| 2588 | 3425 |
| 2589 IndexedDBBackingStore::Transaction::~Transaction() {} | 3426 IndexedDBBackingStore::Transaction::~Transaction() { |
| 3427 BlobChangeMap::iterator iter = blob_change_map_.begin(); | |
| 3428 for (; iter != blob_change_map_.end(); ++iter) { | |
| 3429 delete iter->second; | |
| 3430 } | |
| 3431 } | |
| 2590 | 3432 |
| 2591 void IndexedDBBackingStore::Transaction::Begin() { | 3433 void IndexedDBBackingStore::Transaction::Begin() { |
| 2592 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); | 3434 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); |
| 2593 DCHECK(!transaction_.get()); | 3435 DCHECK(!transaction_.get()); |
| 2594 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); | 3436 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); |
| 2595 } | 3437 } |
| 2596 | 3438 |
| 2597 bool IndexedDBBackingStore::Transaction::Commit() { | 3439 static GURL getURLFromUUID(const string& uuid) { |
| 2598 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); | 3440 return GURL("blob:uuid/" + uuid); |
| 2599 DCHECK(transaction_.get()); | 3441 } |
| 3442 | |
| 3443 void IndexedDBBackingStore::Transaction::BlobChangeRecord::SetBlobInfo( | |
| 3444 std::vector<IndexedDBBlobInfo>* blob_info) { | |
| 3445 blob_info_.clear(); | |
| 3446 if (blob_info) | |
| 3447 blob_info_.swap(*blob_info); | |
| 3448 } | |
| 3449 | |
| 3450 void IndexedDBBackingStore::Transaction::BlobChangeRecord::SetHandles( | |
| 3451 ScopedVector<webkit_blob::BlobDataHandle>* handles) { | |
| 3452 handles_.clear(); | |
| 3453 if (handles) | |
| 3454 handles_.swap(*handles); | |
| 3455 } | |
| 3456 | |
| 3457 bool IndexedDBBackingStore::Transaction::HandleBlobPreTransaction( | |
| 3458 BlobEntryKeyValuePairVec* new_blob_entries, | |
| 3459 WriteDescriptorVec* new_files_to_write) { | |
| 3460 BlobChangeMap::iterator iter = blob_change_map_.begin(); | |
| 3461 new_blob_entries->clear(); | |
| 3462 new_files_to_write->clear(); | |
| 3463 if (iter != blob_change_map_.end()) { | |
| 3464 // Create LevelDBTransaction for the name generator seed and add-journal. | |
| 3465 scoped_refptr<LevelDBTransaction> pre_transaction = | |
| 3466 new LevelDBTransaction(backing_store_->db_.get()); | |
| 3467 BlobJournalType journal; | |
| 3468 for (; iter != blob_change_map_.end(); ++iter) { | |
| 3469 std::vector<IndexedDBBlobInfo>::iterator info_iter; | |
| 3470 std::vector<IndexedDBBlobInfo*> new_blob_keys; | |
| 3471 for (info_iter = iter->second->mutable_blob_info().begin(); | |
| 3472 info_iter != iter->second->mutable_blob_info().end(); ++info_iter) { | |
| 3473 int64 next_blob_key = -1; | |
| 3474 bool result = GetBlobKeyGeneratorCurrentNumber( | |
| 3475 pre_transaction.get(), database_id_, next_blob_key); | |
| 3476 if (!result || next_blob_key < 0) | |
| 3477 return false; | |
| 3478 BlobJournalEntryType journal_entry = | |
| 3479 std::make_pair(database_id_, next_blob_key); | |
| 3480 journal.push_back(journal_entry); | |
| 3481 if (info_iter->is_file()) { | |
| 3482 new_files_to_write->push_back( | |
| 3483 WriteDescriptor(info_iter->file_path(), next_blob_key)); | |
| 3484 } else { | |
| 3485 new_files_to_write->push_back( | |
| 3486 WriteDescriptor( | |
| 3487 getURLFromUUID(info_iter->uuid()), next_blob_key)); | |
| 3488 } | |
| 3489 info_iter->set_key(next_blob_key); | |
| 3490 new_blob_keys.push_back(&*info_iter); | |
| 3491 result = UpdateBlobKeyGeneratorCurrentNumber( | |
| 3492 pre_transaction.get(), database_id_, next_blob_key + 1); | |
| 3493 if (!result) | |
| 3494 return result; | |
| 3495 } | |
| 3496 BlobEntryKey blob_entry_key; | |
| 3497 StringPiece key_piece(iter->second->key()); | |
| 3498 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { | |
| 3499 NOTREACHED(); | |
| 3500 return false; | |
| 3501 } | |
| 3502 new_blob_entries->push_back(std::make_pair(blob_entry_key, | |
| 3503 EncodeBlobData(new_blob_keys))); | |
| 3504 } | |
| 3505 UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal); | |
| 3506 if (!pre_transaction->Commit()) | |
| 3507 return false; | |
| 3508 } | |
| 3509 return true; | |
| 3510 } | |
| 3511 | |
| 3512 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() { | |
| 3513 BlobChangeMap::iterator iter = blob_change_map_.begin(); | |
| 3514 // Look up all old files to remove as part of the transaction, store their | |
| 3515 // names in blobs_to_remove_, and remove their old blob data entries. | |
| 3516 if (iter != blob_change_map_.end()) { | |
| 3517 scoped_ptr<LevelDBIterator> db_iter = transaction_->CreateIterator(); | |
| 3518 for (; iter != blob_change_map_.end(); ++iter) { | |
| 3519 BlobEntryKey blob_entry_key; | |
| 3520 StringPiece key_piece(iter->second->key()); | |
| 3521 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { | |
| 3522 NOTREACHED(); | |
| 3523 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3524 transaction_ = NULL; | |
| 3525 return false; | |
| 3526 } | |
| 3527 if (database_id_ < 0) | |
| 3528 database_id_ = blob_entry_key.database_id(); | |
| 3529 else | |
| 3530 DCHECK_EQ(database_id_, blob_entry_key.database_id()); | |
| 3531 std::string blob_entry_key_bytes = blob_entry_key.Encode(); | |
| 3532 db_iter->Seek(blob_entry_key_bytes); | |
| 3533 if (db_iter->IsValid() && | |
| 3534 !CompareKeys(db_iter->Key(), blob_entry_key_bytes)) { | |
| 3535 std::vector<IndexedDBBlobInfo> blob_info; | |
| 3536 if (!DecodeBlobData(db_iter->Value().as_string(), &blob_info)) { | |
| 3537 INTERNAL_READ_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3538 transaction_ = NULL; | |
| 3539 return false; | |
| 3540 } | |
| 3541 std::vector<IndexedDBBlobInfo>::iterator blob_info_iter; | |
| 3542 for (blob_info_iter = blob_info.begin(); | |
| 3543 blob_info_iter != blob_info.end(); ++blob_info_iter) | |
| 3544 blobs_to_remove_.push_back( | |
| 3545 std::make_pair(database_id_, blob_info_iter->key())); | |
| 3546 transaction_->Remove(blob_entry_key_bytes); | |
| 3547 } | |
| 3548 } | |
| 3549 } | |
| 3550 return true; | |
| 3551 } | |
| 3552 | |
| 3553 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper : | |
| 3554 public IndexedDBBackingStore::BlobWriteCallback { | |
| 3555 public: | |
| 3556 BlobWriteCallbackWrapper( | |
| 3557 IndexedDBBackingStore::Transaction* transaction, | |
| 3558 scoped_refptr<BlobWriteCallback> callback) | |
| 3559 : transaction_(transaction), | |
| 3560 callback_(callback) { | |
| 3561 } | |
| 3562 virtual void didSucceed() { | |
| 3563 callback_->didSucceed(); | |
| 3564 transaction_->chained_blob_writer_ = NULL; | |
| 3565 } | |
| 3566 virtual void didFail() { | |
| 3567 callback_->didFail(); | |
| 3568 transaction_->chained_blob_writer_ = NULL; | |
| 3569 } | |
| 3570 private: | |
| 3571 IndexedDBBackingStore::Transaction* transaction_; | |
| 3572 scoped_refptr<BlobWriteCallback> callback_; | |
| 3573 }; | |
| 3574 | |
| 3575 void IndexedDBBackingStore::Transaction::WriteNewBlobs( | |
| 3576 BlobEntryKeyValuePairVec& new_blob_entries, | |
| 3577 WriteDescriptorVec& new_files_to_write, | |
| 3578 scoped_refptr<BlobWriteCallback> callback) { | |
| 3579 DCHECK_GT(new_files_to_write.size(), 0UL); | |
| 3580 DCHECK_GT(database_id_, 0); | |
| 3581 BlobEntryKeyValuePairVec::iterator blob_entry_iter; | |
| 3582 for (blob_entry_iter = new_blob_entries.begin(); | |
| 3583 blob_entry_iter != new_blob_entries.end(); ++blob_entry_iter) { | |
| 3584 // Add the new blob-table entry for each blob to the main transaction, or | |
| 3585 // remove any entry that may exist if there's no new one. | |
| 3586 if (!blob_entry_iter->second.size()) | |
| 3587 transaction_->Remove(blob_entry_iter->first.Encode()); | |
| 3588 else | |
| 3589 transaction_->Put(blob_entry_iter->first.Encode(), | |
| 3590 &blob_entry_iter->second); | |
| 3591 } | |
| 3592 // Creating the writer will start it going asynchronously. | |
| 3593 chained_blob_writer_ = new ChainedBlobWriterImpl(database_id_, backing_store_, | |
| 3594 new_files_to_write, new BlobWriteCallbackWrapper(this, callback)); | |
| 3595 } | |
| 3596 | |
| 3597 bool IndexedDBBackingStore::Transaction::SortBlobsToRemove() { | |
| 3598 IndexedDBActiveBlobRegistry* registry = | |
| 3599 backing_store_->active_blob_registry(); | |
| 3600 BlobJournalType::iterator iter; | |
| 3601 BlobJournalType primary_journal, live_blob_journal; | |
| 3602 for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end(); | |
| 3603 ++iter) { | |
| 3604 if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second)) | |
| 3605 live_blob_journal.push_back(*iter); | |
| 3606 else | |
| 3607 primary_journal.push_back(*iter); | |
| 3608 } | |
| 3609 UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal); | |
| 3610 if (!MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal)) | |
| 3611 return false; | |
| 3612 // To signal how many blobs need attention right now. | |
| 3613 blobs_to_remove_.swap(primary_journal); | |
| 3614 return true; | |
| 3615 } | |
| 3616 | |
| 3617 bool IndexedDBBackingStore::Transaction::CommitPhaseOne( | |
| 3618 scoped_refptr<BlobWriteCallback> callback) { | |
| 3619 IDB_TRACE("IndexedDBBackingStore::Transaction::commit"); | |
| 3620 DCHECK(transaction_); | |
| 3621 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread()); | |
| 3622 | |
| 3623 if (!backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode())) { | |
| 3624 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3625 transaction_ = NULL; | |
| 3626 return false; | |
| 3627 } | |
| 3628 | |
| 3629 BlobEntryKeyValuePairVec new_blob_entries; | |
| 3630 WriteDescriptorVec new_files_to_write; | |
| 3631 // This commits the journal of blob files we're about to add, if any. | |
| 3632 if (!HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write)) { | |
| 3633 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3634 transaction_ = NULL; | |
| 3635 return false; | |
| 3636 } | |
| 3637 | |
| 3638 DCHECK(!new_files_to_write.size() || | |
| 3639 KeyPrefix::IsValidDatabaseId(database_id_)); | |
| 3640 if (!CollectBlobFilesToRemove()) { | |
| 3641 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3642 transaction_ = NULL; | |
| 3643 return false; | |
| 3644 } | |
| 3645 | |
| 3646 if (new_files_to_write.size()) { | |
| 3647 // This kicks off the writes of the new blobs, if any. | |
| 3648 // This call will zero out new_blob_entries and new_files_to_write. | |
| 3649 WriteNewBlobs(new_blob_entries, new_files_to_write, callback); | |
| 3650 // Remove the add journal, if any; once the blobs are written, and we | |
| 3651 // commit, this will do the cleanup. | |
| 3652 ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode()); | |
| 3653 } else { | |
| 3654 callback->didSucceed(); | |
| 3655 } | |
| 3656 | |
| 3657 return true; | |
| 3658 } | |
| 3659 | |
| 3660 bool IndexedDBBackingStore::Transaction::CommitPhaseTwo() { | |
| 3661 if (blobs_to_remove_.size()) | |
| 3662 if (!SortBlobsToRemove()) { | |
| 3663 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3664 transaction_ = NULL; | |
| 3665 return false; | |
| 3666 } | |
| 3667 | |
| 2600 bool result = transaction_->Commit(); | 3668 bool result = transaction_->Commit(); |
| 2601 transaction_ = NULL; | 3669 transaction_ = NULL; |
| 3670 | |
| 2602 if (!result) | 3671 if (!result) |
| 2603 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | 3672 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); |
| 3673 else if (blobs_to_remove_.size()) | |
| 3674 backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 3675 | |
| 2604 return result; | 3676 return result; |
| 2605 } | 3677 } |
| 2606 | 3678 |
| 2607 void IndexedDBBackingStore::Transaction::Rollback() { | 3679 void IndexedDBBackingStore::Transaction::Rollback() { |
| 2608 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 3680 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); |
| 2609 DCHECK(transaction_.get()); | 3681 DCHECK(transaction_.get()); |
| 3682 if (chained_blob_writer_) { | |
| 3683 chained_blob_writer_->Abort(); | |
| 3684 chained_blob_writer_ = NULL; | |
| 3685 } | |
| 2610 transaction_->Rollback(); | 3686 transaction_->Rollback(); |
| 2611 transaction_ = NULL; | 3687 transaction_ = NULL; |
| 2612 } | 3688 } |
| 2613 | 3689 |
| 3690 // This is storing an info, even if empty, even if the previous key had no blob | |
| 3691 // info that we know of. It duplicates a bunch of information stored in the | |
| 3692 // leveldb transaction, but only w.r.t. the user keys altered--we don't keep the | |
| 3693 // changes to exists or index keys here. | |
| 3694 void IndexedDBBackingStore::Transaction::PutBlobInfo( | |
| 3695 int64 database_id, | |
| 3696 int64 object_store_id, | |
| 3697 const std::string& key, | |
| 3698 std::vector<IndexedDBBlobInfo>* blob_info, | |
| 3699 ScopedVector<webkit_blob::BlobDataHandle>* handles) { | |
| 3700 DCHECK_GT(key.size(), 0UL); | |
| 3701 if (database_id_ < 0) | |
| 3702 database_id_ = database_id; | |
| 3703 DCHECK_EQ(database_id_, database_id); | |
| 3704 | |
| 3705 BlobChangeMap::iterator it = blob_change_map_.find(key); | |
| 3706 BlobChangeRecord *record = NULL; | |
| 3707 if (it == blob_change_map_.end()) { | |
| 3708 record = new BlobChangeRecord(); | |
| 3709 blob_change_map_[key] = record; | |
| 3710 record->set_key(key); | |
| 3711 record->set_object_store_id(object_store_id); | |
| 3712 } else { | |
| 3713 record = it->second; | |
| 3714 } | |
| 3715 DCHECK_EQ(record->object_store_id(), object_store_id); | |
| 3716 record->SetBlobInfo(blob_info); | |
| 3717 record->SetHandles(handles); | |
| 3718 DCHECK(!handles || !handles->size()); | |
| 3719 } | |
| 3720 | |
| 3721 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3722 const GURL& url, int64_t key) | |
| 3723 : is_file_(false), | |
| 3724 url_(url), | |
| 3725 key_(key) | |
| 3726 { | |
| 3727 } | |
| 3728 | |
| 3729 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3730 const FilePath& file_path, int64_t key) | |
| 3731 : is_file_(true), | |
| 3732 file_path_(file_path), | |
| 3733 key_(key) | |
| 3734 { | |
| 3735 } | |
| 3736 | |
| 2614 } // namespace content | 3737 } // namespace content |
| OLD | NEW |