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 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 253 | 253 |
| 254 ServiceWorkerStatusCode ServiceWorkerDatabase::GetNextAvailableIds( | 254 ServiceWorkerStatusCode ServiceWorkerDatabase::GetNextAvailableIds( |
| 255 int64* next_avail_registration_id, | 255 int64* next_avail_registration_id, |
| 256 int64* next_avail_version_id, | 256 int64* next_avail_version_id, |
| 257 int64* next_avail_resource_id) { | 257 int64* next_avail_resource_id) { |
| 258 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 258 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 259 DCHECK(next_avail_registration_id); | 259 DCHECK(next_avail_registration_id); |
| 260 DCHECK(next_avail_version_id); | 260 DCHECK(next_avail_version_id); |
| 261 DCHECK(next_avail_resource_id); | 261 DCHECK(next_avail_resource_id); |
| 262 | 262 |
| 263 if (!LazyOpen(false)) { | 263 ServiceWorkerStatusCode status = LazyOpen(false); |
| 264 if (is_disabled_) | 264 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || |
| 265 return SERVICE_WORKER_ERROR_FAILED; | 265 (status == SERVICE_WORKER_OK && !is_initialized_)) { |
| 266 // Database has never been used. | 266 // Database has never been used. |
| 267 *next_avail_registration_id = 0; | 267 *next_avail_registration_id = 0; |
| 268 *next_avail_version_id = 0; | 268 *next_avail_version_id = 0; |
| 269 *next_avail_resource_id = 0; | 269 *next_avail_resource_id = 0; |
| 270 return SERVICE_WORKER_OK; | 270 return SERVICE_WORKER_OK; |
| 271 } | 271 } |
| 272 if (status != SERVICE_WORKER_OK) | |
| 273 return status; | |
| 272 | 274 |
| 273 ServiceWorkerStatusCode status = | 275 status = ReadNextAvailableId(kNextRegIdKey, &next_avail_registration_id_); |
| 274 ReadNextAvailableId(kNextRegIdKey, &next_avail_registration_id_); | |
| 275 if (status != SERVICE_WORKER_OK) | 276 if (status != SERVICE_WORKER_OK) |
| 276 return status; | 277 return status; |
| 277 status = ReadNextAvailableId(kNextVerIdKey, &next_avail_version_id_); | 278 status = ReadNextAvailableId(kNextVerIdKey, &next_avail_version_id_); |
| 278 if (status != SERVICE_WORKER_OK) | 279 if (status != SERVICE_WORKER_OK) |
| 279 return status; | 280 return status; |
| 280 status = ReadNextAvailableId(kNextResIdKey, &next_avail_resource_id_); | 281 status = ReadNextAvailableId(kNextResIdKey, &next_avail_resource_id_); |
| 281 if (status != SERVICE_WORKER_OK) | 282 if (status != SERVICE_WORKER_OK) |
| 282 return status; | 283 return status; |
| 283 | 284 |
| 284 *next_avail_registration_id = next_avail_registration_id_; | 285 *next_avail_registration_id = next_avail_registration_id_; |
| 285 *next_avail_version_id = next_avail_version_id_; | 286 *next_avail_version_id = next_avail_version_id_; |
| 286 *next_avail_resource_id = next_avail_resource_id_; | 287 *next_avail_resource_id = next_avail_resource_id_; |
| 287 return SERVICE_WORKER_OK; | 288 return SERVICE_WORKER_OK; |
| 288 } | 289 } |
| 289 | 290 |
| 290 ServiceWorkerStatusCode ServiceWorkerDatabase::GetOriginsWithRegistrations( | 291 ServiceWorkerStatusCode ServiceWorkerDatabase::GetOriginsWithRegistrations( |
| 291 std::set<GURL>* origins) { | 292 std::set<GURL>* origins) { |
| 292 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 293 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 293 DCHECK(origins); | 294 DCHECK(origins); |
| 294 | 295 |
| 295 if (!LazyOpen(false)) { | 296 ServiceWorkerStatusCode status = LazyOpen(false); |
| 296 if (is_disabled_) | 297 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || |
| 297 return SERVICE_WORKER_ERROR_FAILED; | 298 (status == SERVICE_WORKER_OK && !is_initialized_)) { |
| 298 // Database has never been used. | 299 // Database has never been used. |
| 299 origins->clear(); | 300 origins->clear(); |
|
michaeln
2014/05/15 19:59:30
if origins needs to be cleared here, then it also
nhiroki
2014/05/16 02:11:11
Done.
| |
| 300 return SERVICE_WORKER_OK; | 301 return SERVICE_WORKER_OK; |
| 301 } | 302 } |
| 303 if (status != SERVICE_WORKER_OK) | |
| 304 return status; | |
| 302 | 305 |
| 303 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | 306 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
| 304 for (itr->Seek(kUniqueOriginKey); itr->Valid(); itr->Next()) { | 307 for (itr->Seek(kUniqueOriginKey); itr->Valid(); itr->Next()) { |
| 305 if (!itr->status().ok()) { | 308 if (!itr->status().ok()) { |
| 306 HandleError(FROM_HERE, itr->status()); | 309 HandleError(FROM_HERE, itr->status()); |
| 307 origins->clear(); | 310 origins->clear(); |
| 308 return LevelDBStatusToServiceWorkerStatusCode(itr->status()); | 311 return LevelDBStatusToServiceWorkerStatusCode(itr->status()); |
| 309 } | 312 } |
| 310 | 313 |
| 311 std::string origin; | 314 std::string origin; |
| 312 if (!RemovePrefix(itr->key().ToString(), kUniqueOriginKey, &origin)) | 315 if (!RemovePrefix(itr->key().ToString(), kUniqueOriginKey, &origin)) |
| 313 break; | 316 break; |
| 314 origins->insert(GURL(origin)); | 317 origins->insert(GURL(origin)); |
| 315 } | 318 } |
| 316 return SERVICE_WORKER_OK; | 319 return SERVICE_WORKER_OK; |
| 317 } | 320 } |
| 318 | 321 |
| 319 bool ServiceWorkerDatabase::GetRegistrationsForOrigin( | 322 ServiceWorkerStatusCode ServiceWorkerDatabase::GetRegistrationsForOrigin( |
| 320 const GURL& origin, | 323 const GURL& origin, |
| 321 std::vector<RegistrationData>* registrations) { | 324 std::vector<RegistrationData>* registrations) { |
| 322 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 325 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 323 DCHECK(registrations); | 326 DCHECK(registrations); |
| 324 | 327 |
| 325 if (!LazyOpen(false)) { | 328 ServiceWorkerStatusCode status = LazyOpen(false); |
| 326 if (is_disabled_) | 329 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || |
| 327 return false; | 330 (status == SERVICE_WORKER_OK && !is_initialized_)) { |
| 328 // Database has never been used. | 331 // Database has never been used. |
| 329 registrations->clear(); | 332 registrations->clear(); |
|
michaeln
2014/05/15 19:59:30
ditto clearing the collection
nhiroki
2014/05/16 02:11:11
Done.
| |
| 330 return true; | 333 return SERVICE_WORKER_OK; |
| 331 } | 334 } |
| 335 if (status != SERVICE_WORKER_OK) | |
| 336 return status; | |
| 332 | 337 |
| 333 // Create a key prefix for registrations. | 338 // Create a key prefix for registrations. |
| 334 std::string prefix = base::StringPrintf( | 339 std::string prefix = base::StringPrintf( |
| 335 "%s%s%c", kRegKeyPrefix, origin.spec().c_str(), kKeySeparator); | 340 "%s%s%c", kRegKeyPrefix, origin.spec().c_str(), kKeySeparator); |
| 336 | 341 |
| 337 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | 342 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
| 338 for (itr->Seek(prefix); itr->Valid(); itr->Next()) { | 343 for (itr->Seek(prefix); itr->Valid(); itr->Next()) { |
| 339 if (!itr->status().ok()) { | 344 if (!itr->status().ok()) { |
| 340 HandleError(FROM_HERE, itr->status()); | 345 HandleError(FROM_HERE, itr->status()); |
| 341 registrations->clear(); | 346 registrations->clear(); |
| 342 return false; | 347 return LevelDBStatusToServiceWorkerStatusCode(itr->status()); |
| 343 } | 348 } |
| 344 | 349 |
| 345 if (!RemovePrefix(itr->key().ToString(), prefix, NULL)) | 350 if (!RemovePrefix(itr->key().ToString(), prefix, NULL)) |
| 346 break; | 351 break; |
| 347 | 352 |
| 348 RegistrationData registration; | 353 RegistrationData registration; |
| 349 if (!ParseRegistrationData(itr->value().ToString(), ®istration)) { | 354 if (!ParseRegistrationData(itr->value().ToString(), ®istration)) { |
| 350 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); | 355 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); |
| 351 registrations->clear(); | 356 registrations->clear(); |
| 352 return false; | 357 return SERVICE_WORKER_ERROR_DB_CORRUPTED; |
| 353 } | 358 } |
| 354 registrations->push_back(registration); | 359 registrations->push_back(registration); |
| 355 } | 360 } |
| 356 return true; | 361 return SERVICE_WORKER_OK; |
| 357 } | 362 } |
| 358 | 363 |
| 359 bool ServiceWorkerDatabase::GetAllRegistrations( | 364 ServiceWorkerStatusCode ServiceWorkerDatabase::GetAllRegistrations( |
| 360 std::vector<RegistrationData>* registrations) { | 365 std::vector<RegistrationData>* registrations) { |
| 361 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 366 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 362 DCHECK(registrations); | 367 DCHECK(registrations); |
| 363 | 368 |
| 364 if (!LazyOpen(false)) { | 369 ServiceWorkerStatusCode status = LazyOpen(false); |
| 365 if (is_disabled_) | 370 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || |
| 366 return false; | 371 (status == SERVICE_WORKER_OK && !is_initialized_)) { |
| 367 // Database has never been used. | 372 // Database has never been used. |
| 368 registrations->clear(); | 373 registrations->clear(); |
|
michaeln
2014/05/15 19:59:30
ditt
nhiroki
2014/05/16 02:11:11
Done.
| |
| 369 return true; | 374 return SERVICE_WORKER_OK; |
| 370 } | 375 } |
| 376 if (status != SERVICE_WORKER_OK) | |
| 377 return status; | |
| 371 | 378 |
| 372 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | 379 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
| 373 for (itr->Seek(kRegKeyPrefix); itr->Valid(); itr->Next()) { | 380 for (itr->Seek(kRegKeyPrefix); itr->Valid(); itr->Next()) { |
| 374 if (!itr->status().ok()) { | 381 if (!itr->status().ok()) { |
| 375 HandleError(FROM_HERE, itr->status()); | 382 HandleError(FROM_HERE, itr->status()); |
| 376 registrations->clear(); | 383 registrations->clear(); |
| 377 return false; | 384 return LevelDBStatusToServiceWorkerStatusCode(itr->status()); |
| 378 } | 385 } |
| 379 | 386 |
| 380 if (!RemovePrefix(itr->key().ToString(), kRegKeyPrefix, NULL)) | 387 if (!RemovePrefix(itr->key().ToString(), kRegKeyPrefix, NULL)) |
| 381 break; | 388 break; |
| 382 | 389 |
| 383 RegistrationData registration; | 390 RegistrationData registration; |
| 384 if (!ParseRegistrationData(itr->value().ToString(), ®istration)) { | 391 if (!ParseRegistrationData(itr->value().ToString(), ®istration)) { |
| 385 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); | 392 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); |
| 386 registrations->clear(); | 393 registrations->clear(); |
| 387 return false; | 394 return SERVICE_WORKER_ERROR_DB_CORRUPTED; |
| 388 } | 395 } |
| 389 registrations->push_back(registration); | 396 registrations->push_back(registration); |
| 390 } | 397 } |
| 391 return true; | 398 return SERVICE_WORKER_OK; |
| 392 } | 399 } |
| 393 | 400 |
| 394 bool ServiceWorkerDatabase::ReadRegistration( | 401 bool ServiceWorkerDatabase::ReadRegistration( |
| 395 int64 registration_id, | 402 int64 registration_id, |
| 396 const GURL& origin, | 403 const GURL& origin, |
| 397 RegistrationData* registration, | 404 RegistrationData* registration, |
| 398 std::vector<ResourceRecord>* resources) { | 405 std::vector<ResourceRecord>* resources) { |
| 399 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 406 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 400 DCHECK(registration); | 407 DCHECK(registration); |
| 401 DCHECK(resources); | 408 DCHECK(resources); |
| 402 | 409 |
| 403 if (!LazyOpen(false) || is_disabled_) | 410 ServiceWorkerStatusCode status = LazyOpen(false); |
| 411 if (status != SERVICE_WORKER_OK || !is_initialized_) | |
| 404 return false; | 412 return false; |
| 405 | 413 |
| 406 RegistrationData value; | 414 RegistrationData value; |
| 407 if (!ReadRegistrationData(registration_id, origin, &value)) | 415 if (!ReadRegistrationData(registration_id, origin, &value)) |
| 408 return false; | 416 return false; |
| 409 | 417 |
| 410 if (!ReadResourceRecords(value.version_id, resources)) | 418 if (!ReadResourceRecords(value.version_id, resources)) |
| 411 return false; | 419 return false; |
| 412 | 420 |
| 413 *registration = value; | 421 *registration = value; |
| 414 return true; | 422 return true; |
| 415 } | 423 } |
| 416 | 424 |
| 417 bool ServiceWorkerDatabase::WriteRegistration( | 425 bool ServiceWorkerDatabase::WriteRegistration( |
| 418 const RegistrationData& registration, | 426 const RegistrationData& registration, |
| 419 const std::vector<ResourceRecord>& resources) { | 427 const std::vector<ResourceRecord>& resources) { |
| 420 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 428 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 421 if (!LazyOpen(true) || is_disabled_) | 429 if (LazyOpen(true) != SERVICE_WORKER_OK) |
| 422 return false; | 430 return false; |
| 423 | 431 |
| 424 leveldb::WriteBatch batch; | 432 leveldb::WriteBatch batch; |
| 425 BumpNextRegistrationIdIfNeeded(registration.registration_id, &batch); | 433 BumpNextRegistrationIdIfNeeded(registration.registration_id, &batch); |
| 426 BumpNextVersionIdIfNeeded(registration.version_id, &batch); | 434 BumpNextVersionIdIfNeeded(registration.version_id, &batch); |
| 427 | 435 |
| 428 // TODO(nhiroki): Skip to add the origin into the unique origin list if it | 436 // TODO(nhiroki): Skip to add the origin into the unique origin list if it |
| 429 // has already been added. | 437 // has already been added. |
| 430 PutUniqueOriginToBatch(registration.scope.GetOrigin(), &batch); | 438 PutUniqueOriginToBatch(registration.scope.GetOrigin(), &batch); |
| 431 | 439 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 467 batch.Delete(CreateResourceIdKey( | 475 batch.Delete(CreateResourceIdKey( |
| 468 kUncommittedResIdKeyPrefix, itr->resource_id)); | 476 kUncommittedResIdKeyPrefix, itr->resource_id)); |
| 469 } | 477 } |
| 470 | 478 |
| 471 return WriteBatch(&batch); | 479 return WriteBatch(&batch); |
| 472 } | 480 } |
| 473 | 481 |
| 474 bool ServiceWorkerDatabase::UpdateVersionToActive(int64 registration_id, | 482 bool ServiceWorkerDatabase::UpdateVersionToActive(int64 registration_id, |
| 475 const GURL& origin) { | 483 const GURL& origin) { |
| 476 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 484 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 477 if (!LazyOpen(false) || is_disabled_) | 485 if (LazyOpen(false) != SERVICE_WORKER_OK || !is_initialized_) |
| 478 return false; | 486 return false; |
| 479 | 487 |
| 480 RegistrationData registration; | 488 RegistrationData registration; |
| 481 if (!ReadRegistrationData(registration_id, origin, ®istration)) | 489 if (!ReadRegistrationData(registration_id, origin, ®istration)) |
| 482 return false; | 490 return false; |
| 483 | 491 |
| 484 registration.is_active = true; | 492 registration.is_active = true; |
| 485 | 493 |
| 486 leveldb::WriteBatch batch; | 494 leveldb::WriteBatch batch; |
| 487 PutRegistrationDataToBatch(registration, &batch); | 495 PutRegistrationDataToBatch(registration, &batch); |
| 488 return WriteBatch(&batch); | 496 return WriteBatch(&batch); |
| 489 } | 497 } |
| 490 | 498 |
| 491 bool ServiceWorkerDatabase::UpdateLastCheckTime(int64 registration_id, | 499 bool ServiceWorkerDatabase::UpdateLastCheckTime(int64 registration_id, |
| 492 const GURL& origin, | 500 const GURL& origin, |
| 493 const base::Time& time) { | 501 const base::Time& time) { |
| 494 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 502 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 495 if (!LazyOpen(false) || is_disabled_) | 503 if (LazyOpen(false) != SERVICE_WORKER_OK || !is_initialized_) |
| 496 return false; | 504 return false; |
| 497 | 505 |
| 498 RegistrationData registration; | 506 RegistrationData registration; |
| 499 if (!ReadRegistrationData(registration_id, origin, ®istration)) | 507 if (!ReadRegistrationData(registration_id, origin, ®istration)) |
| 500 return false; | 508 return false; |
| 501 | 509 |
| 502 registration.last_update_check = time; | 510 registration.last_update_check = time; |
| 503 | 511 |
| 504 leveldb::WriteBatch batch; | 512 leveldb::WriteBatch batch; |
| 505 PutRegistrationDataToBatch(registration, &batch); | 513 PutRegistrationDataToBatch(registration, &batch); |
| 506 return WriteBatch(&batch); | 514 return WriteBatch(&batch); |
| 507 } | 515 } |
| 508 | 516 |
| 509 bool ServiceWorkerDatabase::DeleteRegistration(int64 registration_id, | 517 bool ServiceWorkerDatabase::DeleteRegistration(int64 registration_id, |
| 510 const GURL& origin) { | 518 const GURL& origin) { |
| 511 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 519 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 512 if (!LazyOpen(false) || is_disabled_) | 520 ServiceWorkerStatusCode status = LazyOpen(false); |
| 521 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || | |
| 522 (status == SERVICE_WORKER_OK && !is_initialized_)) { | |
| 523 // Database has never been used. | |
| 524 return true; | |
| 525 } | |
| 526 if (status != SERVICE_WORKER_OK || !origin.is_valid()) | |
| 513 return false; | 527 return false; |
| 514 | 528 |
| 515 leveldb::WriteBatch batch; | 529 leveldb::WriteBatch batch; |
| 516 | 530 |
| 517 // Remove |origin| from unique origins if a registration specified by | 531 // Remove |origin| from unique origins if a registration specified by |
| 518 // |registration_id| is the only one for |origin|. | 532 // |registration_id| is the only one for |origin|. |
| 519 // TODO(nhiroki): Check the uniqueness by more efficient way. | 533 // TODO(nhiroki): Check the uniqueness by more efficient way. |
| 520 std::vector<RegistrationData> registrations; | 534 std::vector<RegistrationData> registrations; |
| 521 if (!GetRegistrationsForOrigin(origin, ®istrations)) | 535 if (GetRegistrationsForOrigin(origin, ®istrations) != SERVICE_WORKER_OK) |
| 522 return false; | 536 return false; |
| 523 if (registrations.size() == 1 && | 537 if (registrations.size() == 1 && |
| 524 registrations[0].registration_id == registration_id) { | 538 registrations[0].registration_id == registration_id) { |
| 525 batch.Delete(CreateUniqueOriginKey(origin)); | 539 batch.Delete(CreateUniqueOriginKey(origin)); |
| 526 } | 540 } |
| 527 | 541 |
| 528 // Delete a registration specified by |registration_id|. | 542 // Delete a registration specified by |registration_id|. |
| 529 batch.Delete(CreateRegistrationKey(registration_id, origin)); | 543 batch.Delete(CreateRegistrationKey(registration_id, origin)); |
| 530 | 544 |
| 531 // Delete resource records associated with the registration. | 545 // Delete resource records associated with the registration. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 564 return WriteResourceIds(kPurgeableResIdKeyPrefix, ids); | 578 return WriteResourceIds(kPurgeableResIdKeyPrefix, ids); |
| 565 } | 579 } |
| 566 | 580 |
| 567 bool ServiceWorkerDatabase::ClearPurgeableResourceIds( | 581 bool ServiceWorkerDatabase::ClearPurgeableResourceIds( |
| 568 const std::set<int64>& ids) { | 582 const std::set<int64>& ids) { |
| 569 return DeleteResourceIds(kPurgeableResIdKeyPrefix, ids); | 583 return DeleteResourceIds(kPurgeableResIdKeyPrefix, ids); |
| 570 } | 584 } |
| 571 | 585 |
| 572 bool ServiceWorkerDatabase::DeleteAllDataForOrigin(const GURL& origin) { | 586 bool ServiceWorkerDatabase::DeleteAllDataForOrigin(const GURL& origin) { |
| 573 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 587 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 574 if (!LazyOpen(true) || is_disabled_ || !origin.is_valid()) | 588 ServiceWorkerStatusCode status = LazyOpen(false); |
| 589 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || | |
| 590 (status == SERVICE_WORKER_OK && !is_initialized_)) { | |
| 591 // Database has never been used. | |
| 592 return true; | |
| 593 } | |
| 594 if (status != SERVICE_WORKER_OK || !origin.is_valid()) | |
| 575 return false; | 595 return false; |
| 576 | 596 |
| 577 leveldb::WriteBatch batch; | 597 leveldb::WriteBatch batch; |
| 578 | 598 |
| 579 // Delete from the unique origin list. | 599 // Delete from the unique origin list. |
| 580 batch.Delete(CreateUniqueOriginKey(origin)); | 600 batch.Delete(CreateUniqueOriginKey(origin)); |
| 581 | 601 |
| 582 std::vector<RegistrationData> registrations; | 602 std::vector<RegistrationData> registrations; |
| 583 if (!GetRegistrationsForOrigin(origin, ®istrations)) | 603 if (GetRegistrationsForOrigin(origin, ®istrations) != SERVICE_WORKER_OK) |
| 584 return false; | 604 return false; |
| 585 | 605 |
| 586 // Delete registrations and resource records. | 606 // Delete registrations and resource records. |
| 587 for (std::vector<RegistrationData>::const_iterator itr = | 607 for (std::vector<RegistrationData>::const_iterator itr = |
| 588 registrations.begin(); itr != registrations.end(); ++itr) { | 608 registrations.begin(); itr != registrations.end(); ++itr) { |
| 589 batch.Delete(CreateRegistrationKey(itr->registration_id, origin)); | 609 batch.Delete(CreateRegistrationKey(itr->registration_id, origin)); |
| 590 if (!DeleteResourceRecords(itr->version_id, &batch)) | 610 if (!DeleteResourceRecords(itr->version_id, &batch)) |
| 591 return false; | 611 return false; |
| 592 } | 612 } |
| 593 | 613 |
| 594 return WriteBatch(&batch); | 614 return WriteBatch(&batch); |
| 595 } | 615 } |
| 596 | 616 |
| 597 bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { | 617 ServiceWorkerStatusCode ServiceWorkerDatabase::LazyOpen( |
| 618 bool create_if_missing) { | |
| 598 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 619 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 599 if (IsOpen()) | |
| 600 return true; | |
| 601 | 620 |
| 602 // Do not try to open a database if we tried and failed once. | 621 // Do not try to open a database if we tried and failed once. |
| 603 if (is_disabled_) | 622 if (is_disabled_) |
| 604 return false; | 623 return SERVICE_WORKER_ERROR_FAILED; |
| 624 if (IsOpen()) | |
| 625 return SERVICE_WORKER_OK; | |
| 605 | 626 |
| 606 // When |path_| is empty, open a database in-memory. | 627 // When |path_| is empty, open a database in-memory. |
| 607 bool use_in_memory_db = path_.empty(); | 628 bool use_in_memory_db = path_.empty(); |
| 608 | 629 |
| 609 if (!create_if_needed) { | 630 if (!create_if_missing) { |
| 610 // Avoid opening a database if it does not exist at the |path_|. | 631 // Avoid opening a database if it does not exist at the |path_|. |
| 611 if (use_in_memory_db || | 632 if (use_in_memory_db || |
| 612 !base::PathExists(path_) || | 633 !base::PathExists(path_) || |
| 613 base::IsDirectoryEmpty(path_)) { | 634 base::IsDirectoryEmpty(path_)) { |
| 614 return false; | 635 return SERVICE_WORKER_ERROR_NOT_FOUND; |
| 615 } | 636 } |
| 616 } | 637 } |
| 617 | 638 |
| 618 leveldb::Options options; | 639 leveldb::Options options; |
| 619 options.create_if_missing = create_if_needed; | 640 options.create_if_missing = create_if_missing; |
| 620 if (use_in_memory_db) { | 641 if (use_in_memory_db) { |
| 621 env_.reset(leveldb::NewMemEnv(leveldb::Env::Default())); | 642 env_.reset(leveldb::NewMemEnv(leveldb::Env::Default())); |
| 622 options.env = env_.get(); | 643 options.env = env_.get(); |
| 623 } | 644 } |
| 624 | 645 |
| 625 leveldb::DB* db = NULL; | 646 leveldb::DB* db = NULL; |
| 626 leveldb::Status status = | 647 leveldb::Status db_status = |
| 627 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db); | 648 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db); |
| 628 if (!status.ok()) { | 649 if (!db_status.ok()) { |
| 629 DCHECK(!db); | 650 DCHECK(!db); |
| 630 // TODO(nhiroki): Should we retry to open the database? | 651 // TODO(nhiroki): Should we retry to open the database? |
| 631 HandleError(FROM_HERE, status); | 652 HandleError(FROM_HERE, db_status); |
| 632 return false; | 653 return LevelDBStatusToServiceWorkerStatusCode(db_status); |
| 633 } | 654 } |
| 634 db_.reset(db); | 655 db_.reset(db); |
| 635 | 656 |
| 636 int64 db_version; | 657 int64 db_version; |
| 637 if (!ReadDatabaseVersion(&db_version)) | 658 ServiceWorkerStatusCode status = ReadDatabaseVersion(&db_version); |
| 638 return false; | 659 if (status != SERVICE_WORKER_OK) |
| 660 return status; | |
| 661 DCHECK_LE(0, db_version); | |
| 639 if (db_version > 0) | 662 if (db_version > 0) |
| 640 is_initialized_ = true; | 663 is_initialized_ = true; |
| 641 return true; | 664 return SERVICE_WORKER_OK; |
| 642 } | 665 } |
| 643 | 666 |
| 644 ServiceWorkerStatusCode ServiceWorkerDatabase::ReadNextAvailableId( | 667 ServiceWorkerStatusCode ServiceWorkerDatabase::ReadNextAvailableId( |
| 645 const char* id_key, | 668 const char* id_key, |
| 646 int64* next_avail_id) { | 669 int64* next_avail_id) { |
| 647 DCHECK(id_key); | 670 DCHECK(id_key); |
| 648 DCHECK(next_avail_id); | 671 DCHECK(next_avail_id); |
| 649 | 672 |
| 650 std::string value; | 673 std::string value; |
| 651 leveldb::Status status = db_->Get(leveldb::ReadOptions(), id_key, &value); | 674 leveldb::Status status = db_->Get(leveldb::ReadOptions(), id_key, &value); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 757 } | 780 } |
| 758 return true; | 781 return true; |
| 759 } | 782 } |
| 760 | 783 |
| 761 bool ServiceWorkerDatabase::ReadResourceIds(const char* id_key_prefix, | 784 bool ServiceWorkerDatabase::ReadResourceIds(const char* id_key_prefix, |
| 762 std::set<int64>* ids) { | 785 std::set<int64>* ids) { |
| 763 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 786 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 764 DCHECK(id_key_prefix); | 787 DCHECK(id_key_prefix); |
| 765 DCHECK(ids); | 788 DCHECK(ids); |
| 766 | 789 |
| 767 if (!LazyOpen(false) || is_disabled_) | 790 ServiceWorkerStatusCode status = LazyOpen(false); |
| 791 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || | |
| 792 (status == SERVICE_WORKER_OK && !is_initialized_)) { | |
| 793 // Database has never been used. | |
| 794 ids->clear(); | |
|
michaeln
2014/05/15 19:59:30
ditto clearing collection
nhiroki
2014/05/16 02:11:11
Done.
| |
| 795 return true; | |
| 796 } | |
| 797 if (status != SERVICE_WORKER_OK) | |
| 768 return false; | 798 return false; |
| 769 | 799 |
| 770 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | 800 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
| 771 for (itr->Seek(id_key_prefix); itr->Valid(); itr->Next()) { | 801 for (itr->Seek(id_key_prefix); itr->Valid(); itr->Next()) { |
| 772 if (!itr->status().ok()) { | 802 if (!itr->status().ok()) { |
| 773 HandleError(FROM_HERE, itr->status()); | 803 HandleError(FROM_HERE, itr->status()); |
| 774 ids->clear(); | 804 ids->clear(); |
| 775 return false; | 805 return false; |
| 776 } | 806 } |
| 777 | 807 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 788 ids->insert(resource_id); | 818 ids->insert(resource_id); |
| 789 } | 819 } |
| 790 return true; | 820 return true; |
| 791 } | 821 } |
| 792 | 822 |
| 793 bool ServiceWorkerDatabase::WriteResourceIds(const char* id_key_prefix, | 823 bool ServiceWorkerDatabase::WriteResourceIds(const char* id_key_prefix, |
| 794 const std::set<int64>& ids) { | 824 const std::set<int64>& ids) { |
| 795 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 825 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 796 DCHECK(id_key_prefix); | 826 DCHECK(id_key_prefix); |
| 797 | 827 |
| 798 if (!LazyOpen(true) || is_disabled_) | 828 if (LazyOpen(true) != SERVICE_WORKER_OK) |
| 799 return false; | 829 return false; |
| 800 if (ids.empty()) | 830 if (ids.empty()) |
| 801 return true; | 831 return true; |
| 802 | 832 |
| 803 leveldb::WriteBatch batch; | 833 leveldb::WriteBatch batch; |
| 804 for (std::set<int64>::const_iterator itr = ids.begin(); | 834 for (std::set<int64>::const_iterator itr = ids.begin(); |
| 805 itr != ids.end(); ++itr) { | 835 itr != ids.end(); ++itr) { |
| 806 // Value should be empty. | 836 // Value should be empty. |
| 807 batch.Put(CreateResourceIdKey(id_key_prefix, *itr), ""); | 837 batch.Put(CreateResourceIdKey(id_key_prefix, *itr), ""); |
| 808 } | 838 } |
| 809 return WriteBatch(&batch); | 839 return WriteBatch(&batch); |
| 810 } | 840 } |
| 811 | 841 |
| 812 bool ServiceWorkerDatabase::DeleteResourceIds(const char* id_key_prefix, | 842 bool ServiceWorkerDatabase::DeleteResourceIds(const char* id_key_prefix, |
| 813 const std::set<int64>& ids) { | 843 const std::set<int64>& ids) { |
| 814 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); | 844 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
| 815 DCHECK(id_key_prefix); | 845 DCHECK(id_key_prefix); |
| 816 | 846 |
| 817 if (!LazyOpen(true) || is_disabled_) | 847 ServiceWorkerStatusCode status = LazyOpen(false); |
| 848 if (status == SERVICE_WORKER_ERROR_NOT_FOUND || | |
| 849 (status == SERVICE_WORKER_OK && !is_initialized_)) { | |
| 850 // Database has never been used. | |
| 851 return true; | |
| 852 } | |
| 853 if (status != SERVICE_WORKER_OK) | |
| 818 return false; | 854 return false; |
| 855 | |
| 819 if (ids.empty()) | 856 if (ids.empty()) |
| 820 return true; | 857 return true; |
| 821 | 858 |
| 822 leveldb::WriteBatch batch; | 859 leveldb::WriteBatch batch; |
| 823 for (std::set<int64>::const_iterator itr = ids.begin(); | 860 for (std::set<int64>::const_iterator itr = ids.begin(); |
| 824 itr != ids.end(); ++itr) { | 861 itr != ids.end(); ++itr) { |
| 825 batch.Delete(CreateResourceIdKey(id_key_prefix, *itr)); | 862 batch.Delete(CreateResourceIdKey(id_key_prefix, *itr)); |
| 826 } | 863 } |
| 827 return WriteBatch(&batch); | 864 return WriteBatch(&batch); |
| 828 } | 865 } |
| 829 | 866 |
| 830 bool ServiceWorkerDatabase::ReadDatabaseVersion(int64* db_version) { | 867 ServiceWorkerStatusCode ServiceWorkerDatabase::ReadDatabaseVersion( |
| 868 int64* db_version) { | |
| 831 std::string value; | 869 std::string value; |
| 832 leveldb::Status status = | 870 leveldb::Status status = |
| 833 db_->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value); | 871 db_->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value); |
| 834 if (status.IsNotFound()) { | 872 if (status.IsNotFound()) { |
| 835 // The database hasn't been initialized yet. | 873 // The database hasn't been initialized yet. |
| 836 *db_version = 0; | 874 *db_version = 0; |
| 837 return true; | 875 return SERVICE_WORKER_OK; |
| 838 } | 876 } |
| 839 if (!status.ok()) { | 877 if (!status.ok()) { |
| 840 HandleError(FROM_HERE, status); | 878 HandleError(FROM_HERE, status); |
| 841 return false; | 879 return LevelDBStatusToServiceWorkerStatusCode(status); |
| 842 } | 880 } |
| 843 | 881 |
| 844 int64 parsed; | 882 int64 parsed; |
| 845 if (!base::StringToInt64(value, &parsed)) { | 883 if (!base::StringToInt64(value, &parsed)) { |
| 846 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); | 884 HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); |
| 847 return false; | 885 return SERVICE_WORKER_ERROR_DB_CORRUPTED; |
| 848 } | 886 } |
| 849 | 887 |
| 850 const int kFirstValidVersion = 1; | 888 const int kFirstValidVersion = 1; |
| 851 if (parsed < kFirstValidVersion || kCurrentSchemaVersion < parsed) { | 889 if (parsed < kFirstValidVersion || kCurrentSchemaVersion < parsed) { |
| 852 HandleError(FROM_HERE, leveldb::Status::Corruption("invalid DB version")); | 890 HandleError(FROM_HERE, leveldb::Status::Corruption("invalid DB version")); |
| 853 return false; | 891 return SERVICE_WORKER_ERROR_DB_CORRUPTED; |
| 854 } | 892 } |
| 855 | 893 |
| 856 *db_version = parsed; | 894 *db_version = parsed; |
| 857 return true; | 895 return SERVICE_WORKER_OK; |
| 858 } | 896 } |
| 859 | 897 |
| 860 bool ServiceWorkerDatabase::WriteBatch(leveldb::WriteBatch* batch) { | 898 bool ServiceWorkerDatabase::WriteBatch(leveldb::WriteBatch* batch) { |
| 861 DCHECK(batch); | 899 DCHECK(batch); |
| 862 DCHECK(!is_disabled_); | 900 DCHECK(!is_disabled_); |
| 863 | 901 |
| 864 if (!is_initialized_) { | 902 if (!is_initialized_) { |
| 865 // Write the database schema version. | 903 // Write the database schema version. |
| 866 batch->Put(kDatabaseVersionKey, base::Int64ToString(kCurrentSchemaVersion)); | 904 batch->Put(kDatabaseVersionKey, base::Int64ToString(kCurrentSchemaVersion)); |
| 867 is_initialized_ = true; | 905 is_initialized_ = true; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 903 // TODO(nhiroki): Add an UMA histogram. | 941 // TODO(nhiroki): Add an UMA histogram. |
| 904 DLOG(ERROR) << "Failed at: " << from_here.ToString() | 942 DLOG(ERROR) << "Failed at: " << from_here.ToString() |
| 905 << " with error: " << status.ToString(); | 943 << " with error: " << status.ToString(); |
| 906 is_disabled_ = true; | 944 is_disabled_ = true; |
| 907 if (status.IsCorruption()) | 945 if (status.IsCorruption()) |
| 908 was_corruption_detected_ = true; | 946 was_corruption_detected_ = true; |
| 909 db_.reset(); | 947 db_.reset(); |
| 910 } | 948 } |
| 911 | 949 |
| 912 } // namespace content | 950 } // namespace content |
| OLD | NEW |