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 |