Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/service_worker/service_worker_database.h" | 5 #include "content/browser/service_worker/service_worker_database.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 // | 35 // |
| 36 // key: "INITDATA_NEXT_RESOURCE_ID" | 36 // key: "INITDATA_NEXT_RESOURCE_ID" |
| 37 // value: <int64 'next_available_resource_id'> | 37 // value: <int64 'next_available_resource_id'> |
| 38 // | 38 // |
| 39 // key: "INITDATA_NEXT_VERSION_ID" | 39 // key: "INITDATA_NEXT_VERSION_ID" |
| 40 // value: <int64 'next_available_version_id'> | 40 // value: <int64 'next_available_version_id'> |
| 41 // | 41 // |
| 42 // key: "INITDATA_UNIQUE_ORIGIN:" + <GURL 'origin'> | 42 // key: "INITDATA_UNIQUE_ORIGIN:" + <GURL 'origin'> |
| 43 // value: <empty> | 43 // value: <empty> |
| 44 // | 44 // |
| 45 // key: "PRES:" + <int64 'purgeable_resource_id'> | |
| 46 // value: <empty> | |
| 47 // | |
| 45 // key: "REG:" + <GURL 'origin'> + '\x00' + <int64 'registration_id'> | 48 // key: "REG:" + <GURL 'origin'> + '\x00' + <int64 'registration_id'> |
| 46 // (ex. "REG:http://example.com\x00123456") | 49 // (ex. "REG:http://example.com\x00123456") |
| 47 // value: <ServiceWorkerRegistrationData serialized as a string> | 50 // value: <ServiceWorkerRegistrationData serialized as a string> |
| 51 // | |
| 52 // key: "URES:" + <int64 'uncommitted_resource_id'> | |
| 53 // value: <empty> | |
| 48 | 54 |
| 49 namespace content { | 55 namespace content { |
| 50 | 56 |
| 51 namespace { | 57 namespace { |
| 52 | 58 |
| 53 const char kDatabaseVersionKey[] = "INITDATA_DB_VERSION"; | 59 const char kDatabaseVersionKey[] = "INITDATA_DB_VERSION"; |
| 54 const char kNextRegIdKey[] = "INITDATA_NEXT_REGISTRATION_ID"; | 60 const char kNextRegIdKey[] = "INITDATA_NEXT_REGISTRATION_ID"; |
| 55 const char kNextResIdKey[] = "INITDATA_NEXT_RESOURCE_ID"; | 61 const char kNextResIdKey[] = "INITDATA_NEXT_RESOURCE_ID"; |
| 56 const char kNextVerIdKey[] = "INITDATA_NEXT_VERSION_ID"; | 62 const char kNextVerIdKey[] = "INITDATA_NEXT_VERSION_ID"; |
| 57 const char kUniqueOriginKey[] = "INITDATA_UNIQUE_ORIGIN:"; | 63 const char kUniqueOriginKey[] = "INITDATA_UNIQUE_ORIGIN:"; |
| 58 | 64 |
| 59 const char kRegKeyPrefix[] = "REG:"; | 65 const char kRegKeyPrefix[] = "REG:"; |
| 60 const char kKeySeparator = '\x00'; | 66 const char kKeySeparator = '\x00'; |
| 61 | 67 |
| 68 const char kUncommittedResIdKeyPrefix[] = "URES:"; | |
| 69 const char kPurgeableResIdKeyPrefix[] = "PRES:"; | |
| 70 | |
| 62 const int64 kCurrentSchemaVersion = 1; | 71 const int64 kCurrentSchemaVersion = 1; |
| 63 | 72 |
| 64 bool RemovePrefix(const std::string& str, | 73 bool RemovePrefix(const std::string& str, |
| 65 const std::string& prefix, | 74 const std::string& prefix, |
| 66 std::string* out) { | 75 std::string* out) { |
| 67 if (!StartsWithASCII(str, prefix, true)) | 76 if (!StartsWithASCII(str, prefix, true)) |
| 68 return false; | 77 return false; |
| 69 if (out) | 78 if (out) |
| 70 *out = str.substr(prefix.size()); | 79 *out = str.substr(prefix.size()); |
| 71 return true; | 80 return true; |
| 72 } | 81 } |
| 73 | 82 |
| 74 std::string CreateRegistrationKey(int64 registration_id, | 83 std::string CreateRegistrationKey(int64 registration_id, |
| 75 const GURL& origin) { | 84 const GURL& origin) { |
| 76 return base::StringPrintf("%s%s%c%s", | 85 return base::StringPrintf("%s%s%c%s", |
| 77 kRegKeyPrefix, | 86 kRegKeyPrefix, |
| 78 origin.spec().c_str(), | 87 origin.spec().c_str(), |
| 79 kKeySeparator, | 88 kKeySeparator, |
| 80 base::Int64ToString(registration_id).c_str()); | 89 base::Int64ToString(registration_id).c_str()); |
| 81 } | 90 } |
| 82 | 91 |
| 83 std::string CreateUniqueOriginKey(const GURL& origin) { | 92 std::string CreateUniqueOriginKey(const GURL& origin) { |
| 84 return base::StringPrintf("%s%s", kUniqueOriginKey, origin.spec().c_str()); | 93 return base::StringPrintf("%s%s", kUniqueOriginKey, origin.spec().c_str()); |
| 85 } | 94 } |
| 86 | 95 |
| 96 std::string CreateResourceIdKey(const char* key_prefix, int64 resource_id) { | |
| 97 return base::StringPrintf( | |
| 98 "%s%s", key_prefix, base::Int64ToString(resource_id).c_str()); | |
| 99 } | |
| 100 | |
| 87 void PutRegistrationDataToBatch( | 101 void PutRegistrationDataToBatch( |
| 88 const ServiceWorkerDatabase::RegistrationData& input, | 102 const ServiceWorkerDatabase::RegistrationData& input, |
| 89 leveldb::WriteBatch* batch) { | 103 leveldb::WriteBatch* batch) { |
| 90 DCHECK(batch); | 104 DCHECK(batch); |
| 91 | 105 |
| 92 // Convert RegistrationData to ServiceWorkerRegistrationData. | 106 // Convert RegistrationData to ServiceWorkerRegistrationData. |
| 93 ServiceWorkerRegistrationData data; | 107 ServiceWorkerRegistrationData data; |
| 94 data.set_registration_id(input.registration_id); | 108 data.set_registration_id(input.registration_id); |
| 95 data.set_scope_url(input.scope.spec()); | 109 data.set_scope_url(input.scope.spec()); |
| 96 data.set_script_url(input.script.spec()); | 110 data.set_script_url(input.script.spec()); |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 343 registrations[0].registration_id == registration_id) { | 357 registrations[0].registration_id == registration_id) { |
| 344 batch.Delete(CreateUniqueOriginKey(origin)); | 358 batch.Delete(CreateUniqueOriginKey(origin)); |
| 345 } | 359 } |
| 346 | 360 |
| 347 batch.Delete(CreateRegistrationKey(registration_id, origin)); | 361 batch.Delete(CreateRegistrationKey(registration_id, origin)); |
| 348 | 362 |
| 349 // TODO(nhiroki): Delete ResourceRecords tied with this registration. | 363 // TODO(nhiroki): Delete ResourceRecords tied with this registration. |
| 350 return WriteBatch(&batch); | 364 return WriteBatch(&batch); |
| 351 } | 365 } |
| 352 | 366 |
| 367 bool ServiceWorkerDatabase::GetUncommittedResourceIds(std::set<int64>* ids) { | |
|
michaeln
2014/04/29 23:50:03
I think the only difference between the Uncommitte
nhiroki
2014/04/30 03:05:58
That's right. Added Read/Write/DeleteResourceIds()
| |
| 368 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
| 369 DCHECK(ids); | |
| 370 | |
| 371 if (!LazyOpen(false) || is_disabled_) | |
| 372 return false; | |
| 373 | |
| 374 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | |
| 375 for (itr->Seek(kUncommittedResIdKeyPrefix); itr->Valid(); itr->Next()) { | |
| 376 if (!itr->status().ok()) { | |
| 377 HandleError(FROM_HERE, itr->status()); | |
| 378 ids->clear(); | |
| 379 return false; | |
| 380 } | |
| 381 | |
| 382 std::string key = itr->key().ToString(); | |
| 383 std::string unprefixed; | |
| 384 if (!RemovePrefix(key, kUncommittedResIdKeyPrefix, &unprefixed)) | |
| 385 break; | |
| 386 | |
| 387 int64 resource_id; | |
| 388 if (!base::StringToInt64(unprefixed, &resource_id)) { | |
| 389 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); | |
| 390 ids->clear(); | |
| 391 return false; | |
| 392 } | |
| 393 ids->insert(resource_id); | |
| 394 } | |
| 395 return true; | |
| 396 } | |
| 397 | |
| 398 bool ServiceWorkerDatabase::WriteUncommittedResourceIds( | |
| 399 const std::set<int64>& ids) { | |
| 400 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
| 401 | |
| 402 if (!LazyOpen(true) || is_disabled_) | |
| 403 return false; | |
| 404 if (ids.empty()) | |
| 405 return true; | |
| 406 | |
| 407 leveldb::WriteBatch batch; | |
| 408 for (std::set<int64>::const_iterator itr = ids.begin(); | |
| 409 itr != ids.end(); ++itr) { | |
| 410 // Value should be empty. | |
| 411 batch.Put(CreateResourceIdKey(kUncommittedResIdKeyPrefix, *itr), ""); | |
| 412 } | |
| 413 return WriteBatch(&batch); | |
| 414 } | |
| 415 | |
| 416 bool ServiceWorkerDatabase::ClearUncommittedResourceIds( | |
| 417 const std::set<int64>& ids) { | |
| 418 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
| 419 | |
| 420 if (!LazyOpen(true) || is_disabled_) | |
| 421 return false; | |
| 422 if (ids.empty()) | |
| 423 return true; | |
| 424 | |
| 425 leveldb::WriteBatch batch; | |
| 426 for (std::set<int64>::const_iterator itr = ids.begin(); | |
| 427 itr != ids.end(); ++itr) { | |
| 428 batch.Delete(CreateResourceIdKey(kUncommittedResIdKeyPrefix, *itr)); | |
| 429 } | |
| 430 return WriteBatch(&batch); | |
| 431 } | |
| 432 | |
| 433 bool ServiceWorkerDatabase::GetPurgeableResourceIds(std::set<int64>* ids) { | |
| 434 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
| 435 DCHECK(ids); | |
| 436 | |
| 437 if (!LazyOpen(false) || is_disabled_) | |
| 438 return false; | |
| 439 | |
| 440 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | |
| 441 for (itr->Seek(kPurgeableResIdKeyPrefix); itr->Valid(); itr->Next()) { | |
| 442 if (!itr->status().ok()) { | |
| 443 HandleError(FROM_HERE, itr->status()); | |
| 444 ids->clear(); | |
| 445 return false; | |
| 446 } | |
| 447 | |
| 448 std::string key = itr->key().ToString(); | |
| 449 std::string unprefixed; | |
| 450 if (!RemovePrefix(key, kPurgeableResIdKeyPrefix, &unprefixed)) | |
| 451 break; | |
| 452 | |
| 453 int64 resource_id; | |
| 454 if (!base::StringToInt64(unprefixed, &resource_id)) { | |
| 455 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); | |
| 456 ids->clear(); | |
| 457 return false; | |
| 458 } | |
| 459 ids->insert(resource_id); | |
| 460 } | |
| 461 return true; | |
| 462 } | |
| 463 | |
| 464 bool ServiceWorkerDatabase::WritePurgeableResourceIds( | |
| 465 const std::set<int64>& ids) { | |
| 466 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
| 467 | |
| 468 if (!LazyOpen(true) || is_disabled_) | |
| 469 return false; | |
| 470 if (ids.empty()) | |
| 471 return true; | |
| 472 | |
| 473 leveldb::WriteBatch batch; | |
| 474 for (std::set<int64>::const_iterator itr = ids.begin(); | |
| 475 itr != ids.end(); ++itr) { | |
| 476 // Value should be empty. | |
| 477 batch.Put(CreateResourceIdKey(kPurgeableResIdKeyPrefix, *itr), ""); | |
| 478 } | |
| 479 return WriteBatch(&batch); | |
| 480 } | |
| 481 | |
| 482 bool ServiceWorkerDatabase::ClearPurgeableResourceIds( | |
| 483 const std::set<int64>& ids) { | |
| 484 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
| 485 | |
| 486 if (!LazyOpen(true) || is_disabled_) | |
| 487 return false; | |
| 488 if (ids.empty()) | |
| 489 return true; | |
| 490 | |
| 491 leveldb::WriteBatch batch; | |
| 492 for (std::set<int64>::const_iterator itr = ids.begin(); | |
| 493 itr != ids.end(); ++itr) { | |
| 494 batch.Delete(CreateResourceIdKey(kPurgeableResIdKeyPrefix, *itr)); | |
| 495 } | |
| 496 return WriteBatch(&batch); | |
| 497 } | |
| 498 | |
| 353 bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { | 499 bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { |
| 354 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 500 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 355 if (IsOpen()) | 501 if (IsOpen()) |
| 356 return true; | 502 return true; |
| 357 | 503 |
| 358 // Do not try to open a database if we tried and failed once. | 504 // Do not try to open a database if we tried and failed once. |
| 359 if (is_disabled_) | 505 if (is_disabled_) |
| 360 return false; | 506 return false; |
| 361 | 507 |
| 362 // When |path_| is empty, open a database in-memory. | 508 // When |path_| is empty, open a database in-memory. |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 // TODO(nhiroki): Add an UMA histogram. | 673 // TODO(nhiroki): Add an UMA histogram. |
| 528 DLOG(ERROR) << "Failed at: " << from_here.ToString() | 674 DLOG(ERROR) << "Failed at: " << from_here.ToString() |
| 529 << " with error: " << status.ToString(); | 675 << " with error: " << status.ToString(); |
| 530 is_disabled_ = true; | 676 is_disabled_ = true; |
| 531 if (status.IsCorruption()) | 677 if (status.IsCorruption()) |
| 532 was_corruption_detected_ = true; | 678 was_corruption_detected_ = true; |
| 533 db_.reset(); | 679 db_.reset(); |
| 534 } | 680 } |
| 535 | 681 |
| 536 } // namespace content | 682 } // namespace content |
| OLD | NEW |