Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(230)

Side by Side Diff: content/browser/service_worker/service_worker_database.cc

Issue 303483007: ServiceWorker: Add UMA for ServiceWorkerDatabase (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: revamp (separate read/write operation results) Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h" 13 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h" 15 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h" 17 #include "base/strings/stringprintf.h"
17 #include "content/browser/service_worker/service_worker_database.pb.h" 18 #include "content/browser/service_worker/service_worker_database.pb.h"
18 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 19 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
19 #include "third_party/leveldatabase/src/include/leveldb/db.h" 20 #include "third_party/leveldatabase/src/include/leveldb/db.h"
20 #include "third_party/leveldatabase/src/include/leveldb/env.h" 21 #include "third_party/leveldatabase/src/include/leveldb/env.h"
21 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 22 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 70
70 const char kRegKeyPrefix[] = "REG:"; 71 const char kRegKeyPrefix[] = "REG:";
71 const char kResKeyPrefix[] = "RES:"; 72 const char kResKeyPrefix[] = "RES:";
72 const char kKeySeparator = '\x00'; 73 const char kKeySeparator = '\x00';
73 74
74 const char kUncommittedResIdKeyPrefix[] = "URES:"; 75 const char kUncommittedResIdKeyPrefix[] = "URES:";
75 const char kPurgeableResIdKeyPrefix[] = "PRES:"; 76 const char kPurgeableResIdKeyPrefix[] = "PRES:";
76 77
77 const int64 kCurrentSchemaVersion = 1; 78 const int64 kCurrentSchemaVersion = 1;
78 79
80 // For histogram.
81 const char kOpenResultHistogramLabel[] =
82 "ServiceWorker.Database.OpenResult";
83 const char kReadResultHistogramLabel[] =
84 "ServiceWorker.Database.ReadResult";
85 const char kWriteResultHistogramLabel[] =
86 "ServiceWorker.Database.WriteResult";
michaeln 2014/06/03 02:09:09 I think this set of stats is good.
87
79 bool RemovePrefix(const std::string& str, 88 bool RemovePrefix(const std::string& str,
80 const std::string& prefix, 89 const std::string& prefix,
81 std::string* out) { 90 std::string* out) {
82 if (!StartsWithASCII(str, prefix, true)) 91 if (!StartsWithASCII(str, prefix, true))
83 return false; 92 return false;
84 if (out) 93 if (out)
85 *out = str.substr(prefix.size()); 94 *out = str.substr(prefix.size());
86 return true; 95 return true;
87 } 96 }
88 97
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 // Value should be empty. 170 // Value should be empty.
162 batch->Put(CreateUniqueOriginKey(origin), ""); 171 batch->Put(CreateUniqueOriginKey(origin), "");
163 } 172 }
164 173
165 void PutPurgeableResourceIdToBatch(int64 resource_id, 174 void PutPurgeableResourceIdToBatch(int64 resource_id,
166 leveldb::WriteBatch* batch) { 175 leveldb::WriteBatch* batch) {
167 // Value should be empty. 176 // Value should be empty.
168 batch->Put(CreateResourceIdKey(kPurgeableResIdKeyPrefix, resource_id), ""); 177 batch->Put(CreateResourceIdKey(kPurgeableResIdKeyPrefix, resource_id), "");
169 } 178 }
170 179
171 bool ParseRegistrationData(const std::string& serialized, 180 ServiceWorkerDatabase::Status ParseId(
172 ServiceWorkerDatabase::RegistrationData* out) { 181 const std::string& serialized,
182 int64* out) {
183 DCHECK(out);
184 int64 id;
185 if (!base::StringToInt64(serialized, &id) || id < 0)
186 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
187 *out = id;
188 return ServiceWorkerDatabase::STATUS_OK;
189 }
190
191 ServiceWorkerDatabase::Status ParseDatabaseVersion(
192 const std::string& serialized,
193 int64* out) {
194 DCHECK(out);
195 const int kFirstValidVersion = 1;
196 int64 version;
197 if (!base::StringToInt64(serialized, &version) ||
198 version < kFirstValidVersion ||
199 kCurrentSchemaVersion < version) {
michaeln 2014/06/03 02:09:09 The last case may not necessarily mean corruption,
nhiroki 2014/06/03 06:59:32 Ah, good point! Added special logging for that cas
200 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
201 }
202 *out = version;
203 return ServiceWorkerDatabase::STATUS_OK;
204 }
205
206 ServiceWorkerDatabase::Status ParseRegistrationData(
207 const std::string& serialized,
208 ServiceWorkerDatabase::RegistrationData* out) {
173 DCHECK(out); 209 DCHECK(out);
174 ServiceWorkerRegistrationData data; 210 ServiceWorkerRegistrationData data;
175 if (!data.ParseFromString(serialized)) 211 if (!data.ParseFromString(serialized))
176 return false; 212 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
177 213
178 GURL scope_url(data.scope_url()); 214 GURL scope_url(data.scope_url());
179 GURL script_url(data.script_url()); 215 GURL script_url(data.script_url());
180 if (!scope_url.is_valid() || 216 if (!scope_url.is_valid() ||
181 !script_url.is_valid() || 217 !script_url.is_valid() ||
182 scope_url.GetOrigin() != script_url.GetOrigin()) { 218 scope_url.GetOrigin() != script_url.GetOrigin()) {
183 return false; 219 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
184 } 220 }
185 221
186 // Convert ServiceWorkerRegistrationData to RegistrationData. 222 // Convert ServiceWorkerRegistrationData to RegistrationData.
187 out->registration_id = data.registration_id(); 223 out->registration_id = data.registration_id();
188 out->scope = scope_url; 224 out->scope = scope_url;
189 out->script = script_url; 225 out->script = script_url;
190 out->version_id = data.version_id(); 226 out->version_id = data.version_id();
191 out->is_active = data.is_active(); 227 out->is_active = data.is_active();
192 out->has_fetch_handler = data.has_fetch_handler(); 228 out->has_fetch_handler = data.has_fetch_handler();
193 out->last_update_check = 229 out->last_update_check =
194 base::Time::FromInternalValue(data.last_update_check_time()); 230 base::Time::FromInternalValue(data.last_update_check_time());
195 return true; 231 return ServiceWorkerDatabase::STATUS_OK;
196 } 232 }
197 233
198 bool ParseResourceRecord(const std::string& serialized, 234 ServiceWorkerDatabase::Status ParseResourceRecord(
199 ServiceWorkerDatabase::ResourceRecord* out) { 235 const std::string& serialized,
236 ServiceWorkerDatabase::ResourceRecord* out) {
200 DCHECK(out); 237 DCHECK(out);
201 ServiceWorkerResourceRecord record; 238 ServiceWorkerResourceRecord record;
202 if (!record.ParseFromString(serialized)) 239 if (!record.ParseFromString(serialized))
203 return false; 240 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
204 241
205 GURL url(record.url()); 242 GURL url(record.url());
206 if (!url.is_valid()) 243 if (!url.is_valid())
207 return false; 244 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
208 245
209 // Convert ServiceWorkerResourceRecord to ResourceRecord. 246 // Convert ServiceWorkerResourceRecord to ResourceRecord.
210 out->resource_id = record.resource_id(); 247 out->resource_id = record.resource_id();
211 out->url = url; 248 out->url = url;
212 return true; 249 return ServiceWorkerDatabase::STATUS_OK;
213 } 250 }
214 251
215 ServiceWorkerDatabase::Status LevelDBStatusToStatus( 252 ServiceWorkerDatabase::Status LevelDBStatusToStatus(
216 const leveldb::Status& status) { 253 const leveldb::Status& status) {
217 if (status.ok()) 254 if (status.ok())
218 return ServiceWorkerDatabase::STATUS_OK; 255 return ServiceWorkerDatabase::STATUS_OK;
219 else if (status.IsNotFound()) 256 else if (status.IsNotFound())
220 return ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND; 257 return ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND;
258 else if (status.IsIOError())
259 return ServiceWorkerDatabase::STATUS_ERROR_IO_ERROR;
221 else if (status.IsCorruption()) 260 else if (status.IsCorruption())
222 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED; 261 return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
223 else 262 else
224 return ServiceWorkerDatabase::STATUS_ERROR_FAILED; 263 return ServiceWorkerDatabase::STATUS_ERROR_FAILED;
225 } 264 }
226 265
266 const char* StatusToString(ServiceWorkerDatabase::Status status) {
267 switch (status) {
268 case ServiceWorkerDatabase::STATUS_OK:
269 return "Database OK";
270 case ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND:
271 return "Database not found";
272 case ServiceWorkerDatabase::STATUS_ERROR_IO_ERROR:
273 return "Database IO error";
274 case ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED:
275 return "Database corrupted";
276 case ServiceWorkerDatabase::STATUS_ERROR_FAILED:
277 return "Database operation failed";
278 case ServiceWorkerDatabase::STATUS_ERROR_MAX:
279 NOTREACHED();
280 return "Database unknown error";
281 }
282 NOTREACHED();
283 return "Database unknown error";
284 }
285
286 void ReportOpenResult(
287 const tracked_objects::Location& from_here,
288 ServiceWorkerDatabase::Status status) {
289 if (status != ServiceWorkerDatabase::STATUS_OK) {
290 DLOG(ERROR) << "Failed at: " << from_here.ToString()
291 << " with error: " << StatusToString(status);
292 }
293 UMA_HISTOGRAM_ENUMERATION(kOpenResultHistogramLabel,
294 status,
295 ServiceWorkerDatabase::STATUS_ERROR_MAX);
296 }
297
298 void ReportReadResult(
299 const tracked_objects::Location& from_here,
300 ServiceWorkerDatabase::Status status) {
301 if (status != ServiceWorkerDatabase::STATUS_OK) {
302 DLOG(ERROR) << "Failed at: " << from_here.ToString()
303 << " with error: " << StatusToString(status);
304 }
305 UMA_HISTOGRAM_ENUMERATION(kReadResultHistogramLabel,
306 status,
307 ServiceWorkerDatabase::STATUS_ERROR_MAX);
308 }
309
310 void ReportWriteResult(
311 const tracked_objects::Location& from_here,
312 ServiceWorkerDatabase::Status status) {
313 if (status != ServiceWorkerDatabase::STATUS_OK) {
314 DLOG(ERROR) << "Failed at: " << from_here.ToString()
315 << " with error: " << StatusToString(status);
316 }
317 UMA_HISTOGRAM_ENUMERATION(kWriteResultHistogramLabel,
318 status,
319 ServiceWorkerDatabase::STATUS_ERROR_MAX);
320 }
321
227 } // namespace 322 } // namespace
228 323
229 ServiceWorkerDatabase::RegistrationData::RegistrationData() 324 ServiceWorkerDatabase::RegistrationData::RegistrationData()
230 : registration_id(-1), 325 : registration_id(-1),
231 version_id(-1), 326 version_id(-1),
232 is_active(false), 327 is_active(false),
233 has_fetch_handler(false) { 328 has_fetch_handler(false) {
234 } 329 }
235 330
236 ServiceWorkerDatabase::RegistrationData::~RegistrationData() { 331 ServiceWorkerDatabase::RegistrationData::~RegistrationData() {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 ServiceWorkerDatabase::Status 383 ServiceWorkerDatabase::Status
289 ServiceWorkerDatabase::GetOriginsWithRegistrations(std::set<GURL>* origins) { 384 ServiceWorkerDatabase::GetOriginsWithRegistrations(std::set<GURL>* origins) {
290 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 385 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
291 DCHECK(origins->empty()); 386 DCHECK(origins->empty());
292 387
293 Status status = LazyOpen(false); 388 Status status = LazyOpen(false);
294 if (IsNewOrNonexistentDatabase(status)) 389 if (IsNewOrNonexistentDatabase(status))
295 return STATUS_OK; 390 return STATUS_OK;
296 if (status != STATUS_OK) 391 if (status != STATUS_OK)
297 return status; 392 return status;
393 DCHECK_EQ(STATUS_OK, status);
298 394
299 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); 395 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
300 for (itr->Seek(kUniqueOriginKey); itr->Valid(); itr->Next()) { 396 for (itr->Seek(kUniqueOriginKey); itr->Valid(); itr->Next()) {
301 if (!itr->status().ok()) { 397 status = LevelDBStatusToStatus(itr->status());
302 HandleError(FROM_HERE, itr->status()); 398 if (status != STATUS_OK)
303 origins->clear(); 399 break;
304 return LevelDBStatusToStatus(itr->status());
305 }
306
307 std::string origin; 400 std::string origin;
308 if (!RemovePrefix(itr->key().ToString(), kUniqueOriginKey, &origin)) 401 if (!RemovePrefix(itr->key().ToString(), kUniqueOriginKey, &origin))
309 break; 402 break;
310 origins->insert(GURL(origin)); 403 origins->insert(GURL(origin));
311 } 404 }
312 return STATUS_OK; 405
406 if (status != STATUS_OK) {
407 Disable();
408 origins->clear();
409 }
410
411 ReportReadResult(FROM_HERE, status);
412 return status;
313 } 413 }
314 414
315 ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetRegistrationsForOrigin( 415 ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetRegistrationsForOrigin(
316 const GURL& origin, 416 const GURL& origin,
317 std::vector<RegistrationData>* registrations) { 417 std::vector<RegistrationData>* registrations) {
318 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 418 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
319 DCHECK(registrations->empty()); 419 DCHECK(registrations->empty());
320 420
321 Status status = LazyOpen(false); 421 Status status = LazyOpen(false);
322 if (IsNewOrNonexistentDatabase(status)) 422 if (IsNewOrNonexistentDatabase(status))
323 return STATUS_OK; 423 return STATUS_OK;
324 if (status != STATUS_OK) 424 if (status != STATUS_OK)
325 return status; 425 return status;
426 DCHECK_EQ(STATUS_OK, status);
michaeln 2014/06/03 02:09:09 given line 424, not sure this dcheck is needed
nhiroki 2014/06/03 06:59:32 Removed them.
326 427
327 // Create a key prefix for registrations. 428 // Create a key prefix for registrations.
328 std::string prefix = base::StringPrintf( 429 std::string prefix = base::StringPrintf(
329 "%s%s%c", kRegKeyPrefix, origin.spec().c_str(), kKeySeparator); 430 "%s%s%c", kRegKeyPrefix, origin.spec().c_str(), kKeySeparator);
330 431
331 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); 432 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
332 for (itr->Seek(prefix); itr->Valid(); itr->Next()) { 433 for (itr->Seek(prefix); itr->Valid(); itr->Next()) {
333 if (!itr->status().ok()) { 434 status = LevelDBStatusToStatus(itr->status());
334 HandleError(FROM_HERE, itr->status()); 435 if (status != STATUS_OK ||
335 registrations->clear(); 436 !RemovePrefix(itr->key().ToString(), prefix, NULL)) {
336 return LevelDBStatusToStatus(itr->status()); 437 break;
337 } 438 }
338 439 RegistrationData registration;
339 if (!RemovePrefix(itr->key().ToString(), prefix, NULL)) 440 status = ParseRegistrationData(itr->value().ToString(), &registration);
441 if (status != STATUS_OK)
340 break; 442 break;
341
342 RegistrationData registration;
343 if (!ParseRegistrationData(itr->value().ToString(), &registration)) {
344 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse"));
345 registrations->clear();
346 return STATUS_ERROR_CORRUPTED;
347 }
348 registrations->push_back(registration); 443 registrations->push_back(registration);
349 } 444 }
350 return STATUS_OK; 445
446 if (status != STATUS_OK) {
447 Disable();
448 registrations->clear();
449 }
450
451 ReportReadResult(FROM_HERE, status);
452 return status;
351 } 453 }
352 454
353 ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetAllRegistrations( 455 ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetAllRegistrations(
354 std::vector<RegistrationData>* registrations) { 456 std::vector<RegistrationData>* registrations) {
355 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 457 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
356 DCHECK(registrations->empty()); 458 DCHECK(registrations->empty());
357 459
358 Status status = LazyOpen(false); 460 Status status = LazyOpen(false);
359 if (IsNewOrNonexistentDatabase(status)) 461 if (IsNewOrNonexistentDatabase(status))
360 return STATUS_OK; 462 return STATUS_OK;
361 if (status != STATUS_OK) 463 if (status != STATUS_OK)
362 return status; 464 return status;
465 DCHECK_EQ(STATUS_OK, status);
363 466
364 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); 467 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
365 for (itr->Seek(kRegKeyPrefix); itr->Valid(); itr->Next()) { 468 for (itr->Seek(kRegKeyPrefix); itr->Valid(); itr->Next()) {
366 if (!itr->status().ok()) { 469 status = LevelDBStatusToStatus(itr->status());
367 HandleError(FROM_HERE, itr->status()); 470 if (status != STATUS_OK ||
368 registrations->clear(); 471 !RemovePrefix(itr->key().ToString(), kRegKeyPrefix, NULL)) {
369 return LevelDBStatusToStatus(itr->status()); 472 break;
370 } 473 }
371 474 RegistrationData registration;
372 if (!RemovePrefix(itr->key().ToString(), kRegKeyPrefix, NULL)) 475 status = ParseRegistrationData(itr->value().ToString(), &registration);
476 if (status != STATUS_OK)
373 break; 477 break;
374
375 RegistrationData registration;
376 if (!ParseRegistrationData(itr->value().ToString(), &registration)) {
377 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse"));
378 registrations->clear();
379 return STATUS_ERROR_CORRUPTED;
380 }
381 registrations->push_back(registration); 478 registrations->push_back(registration);
382 } 479 }
383 return STATUS_OK; 480
481 if (status != STATUS_OK) {
482 Disable();
483 registrations->clear();
484 }
485
486 ReportReadResult(FROM_HERE, status);
487 return status;
384 } 488 }
385 489
386 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistration( 490 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistration(
387 int64 registration_id, 491 int64 registration_id,
388 const GURL& origin, 492 const GURL& origin,
389 RegistrationData* registration, 493 RegistrationData* registration,
390 std::vector<ResourceRecord>* resources) { 494 std::vector<ResourceRecord>* resources) {
391 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 495 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
392 DCHECK(registration); 496 DCHECK(registration);
393 DCHECK(resources); 497 DCHECK(resources);
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 } 771 }
668 772
669 leveldb::Options options; 773 leveldb::Options options;
670 options.create_if_missing = create_if_missing; 774 options.create_if_missing = create_if_missing;
671 if (use_in_memory_db) { 775 if (use_in_memory_db) {
672 env_.reset(leveldb::NewMemEnv(leveldb::Env::Default())); 776 env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
673 options.env = env_.get(); 777 options.env = env_.get();
674 } 778 }
675 779
676 leveldb::DB* db = NULL; 780 leveldb::DB* db = NULL;
677 leveldb::Status db_status = 781 Status status = LevelDBStatusToStatus(
678 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db); 782 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
679 if (!db_status.ok()) { 783 ReportOpenResult(FROM_HERE, status);
784 if (status != STATUS_OK) {
680 DCHECK(!db); 785 DCHECK(!db);
681 // TODO(nhiroki): Should we retry to open the database? 786 // TODO(nhiroki): Should we retry to open the database?
682 HandleError(FROM_HERE, db_status); 787 Disable();
683 return LevelDBStatusToStatus(db_status); 788 return status;
684 } 789 }
685 db_.reset(db); 790 db_.reset(db);
686 791
687 int64 db_version; 792 int64 db_version;
688 Status status = ReadDatabaseVersion(&db_version); 793 status = ReadDatabaseVersion(&db_version);
689 if (status != STATUS_OK) 794 if (status != STATUS_OK)
690 return status; 795 return status;
691 DCHECK_LE(0, db_version); 796 DCHECK_LE(0, db_version);
692 if (db_version > 0) 797 if (db_version > 0)
693 state_ = INITIALIZED; 798 state_ = INITIALIZED;
694 return STATUS_OK; 799 return STATUS_OK;
695 } 800 }
696 801
697 bool ServiceWorkerDatabase::IsNewOrNonexistentDatabase( 802 bool ServiceWorkerDatabase::IsNewOrNonexistentDatabase(
698 ServiceWorkerDatabase::Status status) { 803 ServiceWorkerDatabase::Status status) {
699 if (status == STATUS_ERROR_NOT_FOUND) 804 if (status == STATUS_ERROR_NOT_FOUND)
700 return true; 805 return true;
701 if (status == STATUS_OK && state_ == UNINITIALIZED) 806 if (status == STATUS_OK && state_ == UNINITIALIZED)
702 return true; 807 return true;
703 return false; 808 return false;
704 } 809 }
705 810
706 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadNextAvailableId( 811 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadNextAvailableId(
707 const char* id_key, 812 const char* id_key,
708 int64* next_avail_id) { 813 int64* next_avail_id) {
709 DCHECK(id_key); 814 DCHECK(id_key);
710 DCHECK(next_avail_id); 815 DCHECK(next_avail_id);
711 816
712 std::string value; 817 std::string value;
713 leveldb::Status status = db_->Get(leveldb::ReadOptions(), id_key, &value); 818 Status status = LevelDBStatusToStatus(
714 if (status.IsNotFound()) { 819 db_->Get(leveldb::ReadOptions(), id_key, &value));
820 if (status == STATUS_ERROR_NOT_FOUND) {
715 // Nobody has gotten the next resource id for |id_key|. 821 // Nobody has gotten the next resource id for |id_key|.
716 *next_avail_id = 0; 822 *next_avail_id = 0;
823 ReportReadResult(FROM_HERE, STATUS_OK);
717 return STATUS_OK; 824 return STATUS_OK;
825 } else if (status != STATUS_OK) {
826 Disable();
827 ReportReadResult(FROM_HERE, status);
828 return status;
718 } 829 }
719 830
720 if (!status.ok()) { 831 status = ParseId(value, next_avail_id);
721 HandleError(FROM_HERE, status); 832 if (status != STATUS_OK)
722 return LevelDBStatusToStatus(status); 833 Disable();
723 }
724 834
725 int64 parsed; 835 ReportReadResult(FROM_HERE, status);
726 if (!base::StringToInt64(value, &parsed)) { 836 return status;
727 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse"));
728 return STATUS_ERROR_CORRUPTED;
729 }
730
731 *next_avail_id = parsed;
732 return STATUS_OK;
733 } 837 }
734 838
735 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistrationData( 839 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistrationData(
736 int64 registration_id, 840 int64 registration_id,
737 const GURL& origin, 841 const GURL& origin,
738 RegistrationData* registration) { 842 RegistrationData* registration) {
739 DCHECK(registration); 843 DCHECK(registration);
740 844
741 std::string key = CreateRegistrationKey(registration_id, origin); 845 const std::string key = CreateRegistrationKey(registration_id, origin);
742
743 std::string value; 846 std::string value;
744 leveldb::Status status = db_->Get(leveldb::ReadOptions(), key, &value); 847 Status status = LevelDBStatusToStatus(
745 if (!status.ok()) { 848 db_->Get(leveldb::ReadOptions(), key, &value));
746 if (!status.IsNotFound()) 849 if (status == STATUS_ERROR_NOT_FOUND) {
747 HandleError(FROM_HERE, status); 850 ReportReadResult(FROM_HERE, STATUS_OK);
748 return LevelDBStatusToStatus(status); 851 return status;
852 } else if (status != STATUS_OK) {
853 Disable();
854 ReportReadResult(FROM_HERE, status);
855 return status;
749 } 856 }
750 857
751 RegistrationData parsed; 858 status = ParseRegistrationData(value, registration);
752 if (!ParseRegistrationData(value, &parsed)) { 859 if (status != STATUS_OK)
753 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); 860 Disable();
754 return STATUS_ERROR_CORRUPTED;
755 }
756 861
757 *registration = parsed; 862 ReportReadResult(FROM_HERE, status);
758 return STATUS_OK; 863 return status;
759 } 864 }
760 865
761 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceRecords( 866 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceRecords(
762 int64 version_id, 867 int64 version_id,
763 std::vector<ResourceRecord>* resources) { 868 std::vector<ResourceRecord>* resources) {
764 DCHECK(resources); 869 DCHECK(resources->empty());
765 870
766 std::string prefix = CreateResourceRecordKeyPrefix(version_id); 871 Status status = STATUS_OK;
872 const std::string prefix = CreateResourceRecordKeyPrefix(version_id);
873
767 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); 874 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
768 for (itr->Seek(prefix); itr->Valid(); itr->Next()) { 875 for (itr->Seek(prefix); itr->Valid(); itr->Next()) {
769 if (!itr->status().ok()) { 876 status = LevelDBStatusToStatus(itr->status());
770 HandleError(FROM_HERE, itr->status()); 877 if (status != STATUS_OK ||
771 resources->clear(); 878 !RemovePrefix(itr->key().ToString(), prefix, NULL)) {
772 return LevelDBStatusToStatus(itr->status()); 879 break;
773 } 880 }
774 881 ResourceRecord resource;
775 if (!RemovePrefix(itr->key().ToString(), prefix, NULL)) 882 status = ParseResourceRecord(itr->value().ToString(), &resource);
883 if (status != STATUS_OK)
776 break; 884 break;
777
778 ResourceRecord resource;
779 if (!ParseResourceRecord(itr->value().ToString(), &resource)) {
780 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse"));
781 resources->clear();
782 return STATUS_ERROR_CORRUPTED;
783 }
784 resources->push_back(resource); 885 resources->push_back(resource);
785 } 886 }
786 return STATUS_OK; 887
888 if (status != STATUS_OK) {
889 Disable();
890 resources->clear();
891 }
892
893 ReportReadResult(FROM_HERE, status);
894 return status;
787 } 895 }
788 896
789 ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceRecords( 897 ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceRecords(
790 int64 version_id, 898 int64 version_id,
791 std::vector<int64>* newly_purgeable_resources, 899 std::vector<int64>* newly_purgeable_resources,
792 leveldb::WriteBatch* batch) { 900 leveldb::WriteBatch* batch) {
793 DCHECK(batch); 901 DCHECK(batch);
794 902
795 std::string prefix = CreateResourceRecordKeyPrefix(version_id); 903 Status status = STATUS_OK;
904 const std::string prefix = CreateResourceRecordKeyPrefix(version_id);
905
796 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); 906 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
797 for (itr->Seek(prefix); itr->Valid(); itr->Next()) { 907 for (itr->Seek(prefix); itr->Valid(); itr->Next()) {
798 if (!itr->status().ok()) { 908 status = LevelDBStatusToStatus(itr->status());
799 HandleError(FROM_HERE, itr->status()); 909 if (status != STATUS_OK)
800 return LevelDBStatusToStatus(itr->status()); 910 break;
801 }
802 911
803 std::string key = itr->key().ToString(); 912 const std::string key = itr->key().ToString();
804 std::string unprefixed; 913 std::string unprefixed;
805 if (!RemovePrefix(key, prefix, &unprefixed)) 914 if (!RemovePrefix(key, prefix, &unprefixed))
806 break; 915 break;
807 916
808 int64 resource_id; 917 int64 resource_id;
809 if (!base::StringToInt64(unprefixed, &resource_id)) { 918 status = ParseId(unprefixed, &resource_id);
810 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); 919 if (status != STATUS_OK)
811 return STATUS_ERROR_CORRUPTED; 920 break;
812 }
813 921
814 // Remove a resource record. 922 // Remove a resource record.
815 batch->Delete(key); 923 batch->Delete(key);
816 924
817 // Currently resource sharing across versions and registrations is not 925 // Currently resource sharing across versions and registrations is not
818 // supported, so we can purge this without caring about it. 926 // supported, so we can purge this without caring about it.
819 PutPurgeableResourceIdToBatch(resource_id, batch); 927 PutPurgeableResourceIdToBatch(resource_id, batch);
820 newly_purgeable_resources->push_back(resource_id); 928 newly_purgeable_resources->push_back(resource_id);
821 } 929 }
822 return STATUS_OK; 930
931 if (status != STATUS_OK)
932 Disable();
933
934 ReportReadResult(FROM_HERE, status);
935 return status;
823 } 936 }
824 937
825 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceIds( 938 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceIds(
826 const char* id_key_prefix, 939 const char* id_key_prefix,
827 std::set<int64>* ids) { 940 std::set<int64>* ids) {
828 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 941 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
829 DCHECK(id_key_prefix); 942 DCHECK(id_key_prefix);
830 DCHECK(ids->empty()); 943 DCHECK(ids->empty());
831 944
832 Status status = LazyOpen(false); 945 Status status = LazyOpen(false);
833 if (IsNewOrNonexistentDatabase(status)) 946 if (IsNewOrNonexistentDatabase(status))
834 return STATUS_OK; 947 return STATUS_OK;
835 if (status != STATUS_OK) 948 if (status != STATUS_OK)
836 return status; 949 return status;
950 DCHECK_EQ(STATUS_OK, status);
837 951
838 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); 952 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
839 for (itr->Seek(id_key_prefix); itr->Valid(); itr->Next()) { 953 for (itr->Seek(id_key_prefix); itr->Valid(); itr->Next()) {
840 if (!itr->status().ok()) { 954 status = LevelDBStatusToStatus(itr->status());
841 HandleError(FROM_HERE, itr->status()); 955 if (status != STATUS_OK)
842 ids->clear(); 956 break;
843 return LevelDBStatusToStatus(itr->status());
844 }
845 957
846 std::string unprefixed; 958 std::string unprefixed;
847 if (!RemovePrefix(itr->key().ToString(), id_key_prefix, &unprefixed)) 959 if (!RemovePrefix(itr->key().ToString(), id_key_prefix, &unprefixed))
848 break; 960 break;
849 961
850 int64 resource_id; 962 int64 resource_id;
851 if (!base::StringToInt64(unprefixed, &resource_id)) { 963 status = ParseId(unprefixed, &resource_id);
852 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); 964 if (status != STATUS_OK)
853 ids->clear(); 965 break;
854 return STATUS_ERROR_CORRUPTED;
855 }
856 ids->insert(resource_id); 966 ids->insert(resource_id);
857 } 967 }
858 return STATUS_OK; 968
969 if (status != STATUS_OK) {
970 Disable();
971 ids->clear();
972 }
973
974 ReportReadResult(FROM_HERE, status);
975 return status;
859 } 976 }
860 977
861 ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteResourceIds( 978 ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteResourceIds(
862 const char* id_key_prefix, 979 const char* id_key_prefix,
863 const std::set<int64>& ids) { 980 const std::set<int64>& ids) {
864 leveldb::WriteBatch batch; 981 leveldb::WriteBatch batch;
865 Status status = WriteResourceIdsInBatch(id_key_prefix, ids, &batch); 982 Status status = WriteResourceIdsInBatch(id_key_prefix, ids, &batch);
866 if (status != STATUS_OK) 983 if (status != STATUS_OK)
867 return status; 984 return status;
868 return WriteBatch(&batch); 985 return WriteBatch(&batch);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
917 for (std::set<int64>::const_iterator itr = ids.begin(); 1034 for (std::set<int64>::const_iterator itr = ids.begin();
918 itr != ids.end(); ++itr) { 1035 itr != ids.end(); ++itr) {
919 batch->Delete(CreateResourceIdKey(id_key_prefix, *itr)); 1036 batch->Delete(CreateResourceIdKey(id_key_prefix, *itr));
920 } 1037 }
921 return STATUS_OK; 1038 return STATUS_OK;
922 } 1039 }
923 1040
924 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadDatabaseVersion( 1041 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadDatabaseVersion(
925 int64* db_version) { 1042 int64* db_version) {
926 std::string value; 1043 std::string value;
927 leveldb::Status status = 1044 Status status = LevelDBStatusToStatus(
928 db_->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value); 1045 db_->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value));
929 if (status.IsNotFound()) { 1046 if (status == STATUS_ERROR_NOT_FOUND) {
930 // The database hasn't been initialized yet. 1047 // The database hasn't been initialized yet.
931 *db_version = 0; 1048 *db_version = 0;
1049 ReportReadResult(FROM_HERE, STATUS_OK);
932 return STATUS_OK; 1050 return STATUS_OK;
933 } 1051 } else if (status != STATUS_OK) {
934 if (!status.ok()) { 1052 Disable();
935 HandleError(FROM_HERE, status); 1053 ReportReadResult(FROM_HERE, status);
936 return LevelDBStatusToStatus(status); 1054 return status;
937 } 1055 }
938 1056
939 int64 parsed; 1057 status = ParseDatabaseVersion(value, db_version);
940 if (!base::StringToInt64(value, &parsed)) { 1058 if (status != STATUS_OK)
941 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); 1059 Disable();
942 return STATUS_ERROR_CORRUPTED;
943 }
944 1060
945 const int kFirstValidVersion = 1; 1061 ReportReadResult(FROM_HERE, status);
946 if (parsed < kFirstValidVersion || kCurrentSchemaVersion < parsed) { 1062 return status;
947 HandleError(FROM_HERE, leveldb::Status::Corruption("invalid DB version"));
948 return STATUS_ERROR_CORRUPTED;
949 }
950
951 *db_version = parsed;
952 return STATUS_OK;
953 } 1063 }
954 1064
955 ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteBatch( 1065 ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteBatch(
956 leveldb::WriteBatch* batch) { 1066 leveldb::WriteBatch* batch) {
957 DCHECK(batch); 1067 DCHECK(batch);
958 DCHECK_NE(DISABLED, state_); 1068 DCHECK_NE(DISABLED, state_);
959 1069
960 if (state_ == UNINITIALIZED) { 1070 if (state_ == UNINITIALIZED) {
961 // Write the database schema version. 1071 // Write the database schema version.
962 batch->Put(kDatabaseVersionKey, base::Int64ToString(kCurrentSchemaVersion)); 1072 batch->Put(kDatabaseVersionKey, base::Int64ToString(kCurrentSchemaVersion));
963 state_ = INITIALIZED; 1073 state_ = INITIALIZED;
964 } 1074 }
965 1075
966 leveldb::Status status = db_->Write(leveldb::WriteOptions(), batch); 1076 Status status = LevelDBStatusToStatus(
967 if (!status.ok()) 1077 db_->Write(leveldb::WriteOptions(), batch));
968 HandleError(FROM_HERE, status); 1078 if (status != STATUS_OK)
969 return LevelDBStatusToStatus(status); 1079 Disable();
1080
1081 ReportWriteResult(FROM_HERE, status);
1082 return status;
970 } 1083 }
971 1084
972 void ServiceWorkerDatabase::BumpNextRegistrationIdIfNeeded( 1085 void ServiceWorkerDatabase::BumpNextRegistrationIdIfNeeded(
973 int64 used_id, leveldb::WriteBatch* batch) { 1086 int64 used_id, leveldb::WriteBatch* batch) {
974 DCHECK(batch); 1087 DCHECK(batch);
975 if (next_avail_registration_id_ <= used_id) { 1088 if (next_avail_registration_id_ <= used_id) {
976 next_avail_registration_id_ = used_id + 1; 1089 next_avail_registration_id_ = used_id + 1;
977 batch->Put(kNextRegIdKey, base::Int64ToString(next_avail_registration_id_)); 1090 batch->Put(kNextRegIdKey, base::Int64ToString(next_avail_registration_id_));
978 } 1091 }
979 } 1092 }
980 1093
981 void ServiceWorkerDatabase::BumpNextVersionIdIfNeeded( 1094 void ServiceWorkerDatabase::BumpNextVersionIdIfNeeded(
982 int64 used_id, leveldb::WriteBatch* batch) { 1095 int64 used_id, leveldb::WriteBatch* batch) {
983 DCHECK(batch); 1096 DCHECK(batch);
984 if (next_avail_version_id_ <= used_id) { 1097 if (next_avail_version_id_ <= used_id) {
985 next_avail_version_id_ = used_id + 1; 1098 next_avail_version_id_ = used_id + 1;
986 batch->Put(kNextVerIdKey, base::Int64ToString(next_avail_version_id_)); 1099 batch->Put(kNextVerIdKey, base::Int64ToString(next_avail_version_id_));
987 } 1100 }
988 } 1101 }
989 1102
990 bool ServiceWorkerDatabase::IsOpen() { 1103 bool ServiceWorkerDatabase::IsOpen() {
991 return db_ != NULL; 1104 return db_ != NULL;
992 } 1105 }
993 1106
994 void ServiceWorkerDatabase::HandleError( 1107 void ServiceWorkerDatabase::Disable() {
michaeln 2014/06/03 02:09:09 The new code looks correct. It maybe could have be
nhiroki 2014/06/03 06:59:32 SGTM! I'd prefer to work with Handle{...}Result()
995 const tracked_objects::Location& from_here, 1108 DLOG(ERROR) << "ServiceWorkerDatabase is disabled.";
996 const leveldb::Status& status) {
997 // TODO(nhiroki): Add an UMA histogram.
998 DLOG(ERROR) << "Failed at: " << from_here.ToString()
999 << " with error: " << status.ToString();
1000 state_ = DISABLED; 1109 state_ = DISABLED;
1001 db_.reset(); 1110 db_.reset();
1002 } 1111 }
1003 1112
1004 } // namespace content 1113 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/service_worker/service_worker_database.h ('k') | content/browser/service_worker/service_worker_storage.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698