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) { | |
368 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
369 if (!LazyOpen(false) || is_disabled_) | |
370 return false; | |
371 return ReadResourceIds(kUncommittedResIdKeyPrefix, ids); | |
372 } | |
373 | |
374 bool ServiceWorkerDatabase::WriteUncommittedResourceIds( | |
375 const std::set<int64>& ids) { | |
376 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
377 if (!LazyOpen(true) || is_disabled_) | |
378 return false; | |
379 return WriteResourceIds(kUncommittedResIdKeyPrefix, ids); | |
380 } | |
381 | |
382 bool ServiceWorkerDatabase::ClearUncommittedResourceIds( | |
383 const std::set<int64>& ids) { | |
384 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
385 if (!LazyOpen(true) || is_disabled_) | |
386 return false; | |
387 return DeleteResourceIds(kUncommittedResIdKeyPrefix, ids); | |
388 } | |
389 | |
390 bool ServiceWorkerDatabase::GetPurgeableResourceIds(std::set<int64>* ids) { | |
391 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
392 if (!LazyOpen(false) || is_disabled_) | |
393 return false; | |
394 return ReadResourceIds(kPurgeableResIdKeyPrefix, ids); | |
395 } | |
396 | |
397 bool ServiceWorkerDatabase::WritePurgeableResourceIds( | |
398 const std::set<int64>& ids) { | |
399 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
400 if (!LazyOpen(true) || is_disabled_) | |
401 return false; | |
402 return WriteResourceIds(kPurgeableResIdKeyPrefix, ids); | |
403 } | |
404 | |
405 bool ServiceWorkerDatabase::ClearPurgeableResourceIds( | |
406 const std::set<int64>& ids) { | |
407 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | |
408 if (!LazyOpen(true) || is_disabled_) | |
michaeln
2014/04/30 03:23:57
These tests and the dcheck could also be in the co
nhiroki
2014/04/30 04:04:06
That's just my preference. Basically I prefer such
| |
409 return false; | |
410 return DeleteResourceIds(kPurgeableResIdKeyPrefix, ids); | |
411 } | |
412 | |
353 bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { | 413 bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { |
354 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 414 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
355 if (IsOpen()) | 415 if (IsOpen()) |
356 return true; | 416 return true; |
357 | 417 |
358 // Do not try to open a database if we tried and failed once. | 418 // Do not try to open a database if we tried and failed once. |
359 if (is_disabled_) | 419 if (is_disabled_) |
360 return false; | 420 return false; |
361 | 421 |
362 // When |path_| is empty, open a database in-memory. | 422 // When |path_| is empty, open a database in-memory. |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
444 RegistrationData parsed; | 504 RegistrationData parsed; |
445 if (!ParseRegistrationData(value, &parsed)) { | 505 if (!ParseRegistrationData(value, &parsed)) { |
446 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); | 506 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); |
447 return false; | 507 return false; |
448 } | 508 } |
449 | 509 |
450 *registration = parsed; | 510 *registration = parsed; |
451 return true; | 511 return true; |
452 } | 512 } |
453 | 513 |
514 bool ServiceWorkerDatabase::ReadResourceIds(const char* id_key_prefix, | |
515 std::set<int64>* ids) { | |
516 DCHECK(id_key_prefix); | |
517 DCHECK(ids); | |
518 | |
519 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | |
520 for (itr->Seek(id_key_prefix); itr->Valid(); itr->Next()) { | |
521 if (!itr->status().ok()) { | |
522 HandleError(FROM_HERE, itr->status()); | |
523 ids->clear(); | |
524 return false; | |
525 } | |
526 | |
527 std::string unprefixed; | |
528 if (!RemovePrefix(itr->key().ToString(), id_key_prefix, &unprefixed)) | |
529 break; | |
530 | |
531 int64 resource_id; | |
532 if (!base::StringToInt64(unprefixed, &resource_id)) { | |
533 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); | |
534 ids->clear(); | |
535 return false; | |
536 } | |
537 ids->insert(resource_id); | |
538 } | |
539 return true; | |
540 } | |
541 | |
542 bool ServiceWorkerDatabase::WriteResourceIds(const char* id_key_prefix, | |
543 const std::set<int64>& ids) { | |
544 DCHECK(id_key_prefix); | |
545 if (ids.empty()) | |
546 return true; | |
547 leveldb::WriteBatch batch; | |
548 for (std::set<int64>::const_iterator itr = ids.begin(); | |
549 itr != ids.end(); ++itr) { | |
550 // Value should be empty. | |
551 batch.Put(CreateResourceIdKey(id_key_prefix, *itr), ""); | |
552 } | |
553 return WriteBatch(&batch); | |
554 } | |
555 | |
556 bool ServiceWorkerDatabase::DeleteResourceIds(const char* id_key_prefix, | |
557 const std::set<int64>& ids) { | |
558 DCHECK(id_key_prefix); | |
559 if (ids.empty()) | |
560 return true; | |
561 leveldb::WriteBatch batch; | |
562 for (std::set<int64>::const_iterator itr = ids.begin(); | |
563 itr != ids.end(); ++itr) { | |
564 batch.Delete(CreateResourceIdKey(id_key_prefix, *itr)); | |
565 } | |
566 return WriteBatch(&batch); | |
567 } | |
568 | |
454 bool ServiceWorkerDatabase::ReadDatabaseVersion(int64* db_version) { | 569 bool ServiceWorkerDatabase::ReadDatabaseVersion(int64* db_version) { |
455 std::string value; | 570 std::string value; |
456 leveldb::Status status = | 571 leveldb::Status status = |
457 db_->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value); | 572 db_->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value); |
458 if (status.IsNotFound()) { | 573 if (status.IsNotFound()) { |
459 // The database hasn't been initialized yet. | 574 // The database hasn't been initialized yet. |
460 *db_version = 0; | 575 *db_version = 0; |
461 return true; | 576 return true; |
462 } | 577 } |
463 if (!status.ok()) { | 578 if (!status.ok()) { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
527 // TODO(nhiroki): Add an UMA histogram. | 642 // TODO(nhiroki): Add an UMA histogram. |
528 DLOG(ERROR) << "Failed at: " << from_here.ToString() | 643 DLOG(ERROR) << "Failed at: " << from_here.ToString() |
529 << " with error: " << status.ToString(); | 644 << " with error: " << status.ToString(); |
530 is_disabled_ = true; | 645 is_disabled_ = true; |
531 if (status.IsCorruption()) | 646 if (status.IsCorruption()) |
532 was_corruption_detected_ = true; | 647 was_corruption_detected_ = true; |
533 db_.reset(); | 648 db_.reset(); |
534 } | 649 } |
535 | 650 |
536 } // namespace content | 651 } // namespace content |
OLD | NEW |