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