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

Side by Side Diff: components/offline_pages/offline_page_metadata_store_sql.cc

Issue 2497703002: [Offline pages] Resetting offline page metadata store to handle LOAD/INIT failures (Closed)
Patch Set: Addressing feedback from jianli@ and dimich@ Created 4 years, 1 month 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "components/offline_pages/offline_page_metadata_store_sql.h" 5 #include "components/offline_pages/offline_page_metadata_store_sql.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/files/file_path.h" 8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 const std::vector<OfflinePageItem>& result) { 260 const std::vector<OfflinePageItem>& result) {
261 // TODO(fgorski): Switch to SQL specific UMA metrics. 261 // TODO(fgorski): Switch to SQL specific UMA metrics.
262 UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus", status, 262 UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus", status,
263 OfflinePageMetadataStore::LOAD_STATUS_COUNT); 263 OfflinePageMetadataStore::LOAD_STATUS_COUNT);
264 if (status == OfflinePageMetadataStore::LOAD_SUCCEEDED) { 264 if (status == OfflinePageMetadataStore::LOAD_SUCCEEDED) {
265 UMA_HISTOGRAM_COUNTS("OfflinePages.SavedPageCount", 265 UMA_HISTOGRAM_COUNTS("OfflinePages.SavedPageCount",
266 static_cast<int32_t>(result.size())); 266 static_cast<int32_t>(result.size()));
267 } else { 267 } else {
268 DVLOG(1) << "Offline pages database loading failed: " << status; 268 DVLOG(1) << "Offline pages database loading failed: " << status;
269 } 269 }
270 runner->PostTask(FROM_HERE, base::Bind(callback, status, result)); 270 runner->PostTask(FROM_HERE, base::Bind(callback, result));
271 } 271 }
272 272
273 void OpenConnectionSync(sql::Connection* db, 273 void OpenConnectionSync(sql::Connection* db,
274 scoped_refptr<base::SingleThreadTaskRunner> runner, 274 scoped_refptr<base::SingleThreadTaskRunner> runner,
275 const base::FilePath& path, 275 const base::FilePath& path,
276 const base::Callback<void(StoreState)>& callback) { 276 const base::Callback<void(bool)>& callback) {
277 StoreState state = 277 bool success = InitDatabase(db, path);
278 InitDatabase(db, path) ? StoreState::LOADED : StoreState::FAILED_LOADING; 278 runner->PostTask(FROM_HERE, base::Bind(callback, success));
279 runner->PostTask(FROM_HERE, base::Bind(callback, state));
280 } 279 }
281 280
282 bool GetPageByOfflineIdSync(sql::Connection* db, 281 bool GetPageByOfflineIdSync(sql::Connection* db,
283 int64_t offline_id, 282 int64_t offline_id,
284 OfflinePageItem* item) { 283 OfflinePageItem* item) {
285 const char kSql[] = 284 const char kSql[] =
286 "SELECT * FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?"; 285 "SELECT * FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?";
287 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql)); 286 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
288 statement.BindInt64(0, offline_id); 287 statement.BindInt64(0, offline_id);
289 288
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 PostStoreErrorForAllIds(runner, offline_ids, callback); 424 PostStoreErrorForAllIds(runner, offline_ids, callback);
426 return; 425 return;
427 } 426 }
428 427
429 runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result))); 428 runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
430 } 429 }
431 430
432 void ResetSync(sql::Connection* db, 431 void ResetSync(sql::Connection* db,
433 const base::FilePath& db_file_path, 432 const base::FilePath& db_file_path,
434 scoped_refptr<base::SingleThreadTaskRunner> runner, 433 scoped_refptr<base::SingleThreadTaskRunner> runner,
435 const base::Callback<void(StoreState)>& callback) { 434 const base::Callback<void(bool)>& callback) {
436 // This method deletes the content of the whole store and reinitializes it. 435 // This method deletes the content of the whole store and reinitializes it.
437 bool success = db->Raze(); 436 bool success = true;
438 db->Close(); 437 if (db) {
439 StoreState state; 438 success = db->Raze();
440 if (success) { 439 db->Close();
441 state = InitDatabase(db, db_file_path) ? StoreState::LOADED
442 : StoreState::FAILED_LOADING;
443 } else {
444 state = StoreState::FAILED_RESET;
445 } 440 }
446 runner->PostTask(FROM_HERE, base::Bind(callback, state)); 441 success = base::DeleteFile(db_file_path, true /*recursive*/) && success;
442 runner->PostTask(FROM_HERE, base::Bind(callback, success));
447 } 443 }
448 444
449 } // anonymous namespace 445 } // anonymous namespace
450 446
451 OfflinePageMetadataStoreSQL::OfflinePageMetadataStoreSQL( 447 OfflinePageMetadataStoreSQL::OfflinePageMetadataStoreSQL(
452 scoped_refptr<base::SequencedTaskRunner> background_task_runner, 448 scoped_refptr<base::SequencedTaskRunner> background_task_runner,
453 const base::FilePath& path) 449 const base::FilePath& path)
454 : background_task_runner_(std::move(background_task_runner)), 450 : background_task_runner_(std::move(background_task_runner)),
455 db_file_path_(path.AppendASCII("OfflinePages.db")), 451 db_file_path_(path.AppendASCII("OfflinePages.db")),
456 state_(StoreState::NOT_LOADED), 452 state_(StoreState::NOT_LOADED),
457 weak_ptr_factory_(this) { 453 weak_ptr_factory_(this) {
458 OpenConnection();
459 } 454 }
460 455
461 OfflinePageMetadataStoreSQL::~OfflinePageMetadataStoreSQL() { 456 OfflinePageMetadataStoreSQL::~OfflinePageMetadataStoreSQL() {
462 if (db_.get() && 457 if (db_.get() &&
463 !background_task_runner_->DeleteSoon(FROM_HERE, db_.release())) { 458 !background_task_runner_->DeleteSoon(FROM_HERE, db_.release())) {
464 DLOG(WARNING) << "SQL database will not be deleted."; 459 DLOG(WARNING) << "SQL database will not be deleted.";
465 } 460 }
466 } 461 }
467 462
463 void OfflinePageMetadataStoreSQL::Initialize(
464 const InitializeCallback& callback) {
465 DCHECK(!db_);
466 db_.reset(new sql::Connection());
467 background_task_runner_->PostTask(
468 FROM_HERE,
469 base::Bind(&OpenConnectionSync, db_.get(),
470 base::ThreadTaskRunnerHandle::Get(), db_file_path_,
471 base::Bind(&OfflinePageMetadataStoreSQL::OnOpenConnectionDone,
472 weak_ptr_factory_.GetWeakPtr(), callback)));
473 }
474
468 void OfflinePageMetadataStoreSQL::GetOfflinePages( 475 void OfflinePageMetadataStoreSQL::GetOfflinePages(
469 const LoadCallback& callback) { 476 const LoadCallback& callback) {
470 if (!CheckDb(base::Bind( 477 if (!CheckDb()) {
471 callback, STORE_INIT_FAILED, std::vector<OfflinePageItem>()))) { 478 base::ThreadTaskRunnerHandle::Get()->PostTask(
479 FROM_HERE, base::Bind(callback, std::vector<OfflinePageItem>()));
472 return; 480 return;
473 } 481 }
474 482
475 background_task_runner_->PostTask( 483 background_task_runner_->PostTask(
476 FROM_HERE, base::Bind(&GetOfflinePagesSync, db_.get(), 484 FROM_HERE, base::Bind(&GetOfflinePagesSync, db_.get(),
477 base::ThreadTaskRunnerHandle::Get(), callback)); 485 base::ThreadTaskRunnerHandle::Get(), callback));
478 } 486 }
479 487
480 void OfflinePageMetadataStoreSQL::AddOfflinePage( 488 void OfflinePageMetadataStoreSQL::AddOfflinePage(
481 const OfflinePageItem& offline_page, 489 const OfflinePageItem& offline_page,
482 const AddCallback& callback) { 490 const AddCallback& callback) {
483 if (!CheckDb(base::Bind(callback, ItemActionStatus::STORE_ERROR))) 491 if (!CheckDb()) {
492 base::ThreadTaskRunnerHandle::Get()->PostTask(
493 FROM_HERE, base::Bind(callback, ItemActionStatus::STORE_ERROR));
484 return; 494 return;
495 }
485 496
486 background_task_runner_->PostTask( 497 background_task_runner_->PostTask(
487 FROM_HERE, 498 FROM_HERE,
488 base::Bind(&AddOfflinePageSync, db_.get(), 499 base::Bind(&AddOfflinePageSync, db_.get(),
489 base::ThreadTaskRunnerHandle::Get(), offline_page, callback)); 500 base::ThreadTaskRunnerHandle::Get(), offline_page, callback));
490 } 501 }
491 502
492 void OfflinePageMetadataStoreSQL::UpdateOfflinePages( 503 void OfflinePageMetadataStoreSQL::UpdateOfflinePages(
493 const std::vector<OfflinePageItem>& pages, 504 const std::vector<OfflinePageItem>& pages,
494 const UpdateCallback& callback) { 505 const UpdateCallback& callback) {
495 if (!db_.get()) { 506 if (!CheckDb()) {
496 PostStoreErrorForAllPages(base::ThreadTaskRunnerHandle::Get(), pages, 507 PostStoreErrorForAllPages(base::ThreadTaskRunnerHandle::Get(), pages,
497 callback); 508 callback);
498 return; 509 return;
499 } 510 }
500 511
501 background_task_runner_->PostTask( 512 background_task_runner_->PostTask(
502 FROM_HERE, 513 FROM_HERE,
503 base::Bind(&UpdateOfflinePagesSync, db_.get(), 514 base::Bind(&UpdateOfflinePagesSync, db_.get(),
504 base::ThreadTaskRunnerHandle::Get(), pages, callback)); 515 base::ThreadTaskRunnerHandle::Get(), pages, callback));
505 } 516 }
506 517
507 void OfflinePageMetadataStoreSQL::RemoveOfflinePages( 518 void OfflinePageMetadataStoreSQL::RemoveOfflinePages(
508 const std::vector<int64_t>& offline_ids, 519 const std::vector<int64_t>& offline_ids,
509 const UpdateCallback& callback) { 520 const UpdateCallback& callback) {
510 DCHECK(db_.get()); 521 if (!CheckDb()) {
522 PostStoreErrorForAllIds(base::ThreadTaskRunnerHandle::Get(), offline_ids,
523 callback);
524 return;
525 }
511 526
512 if (offline_ids.empty()) { 527 if (offline_ids.empty()) {
513 // Nothing to do, but post a callback instead of calling directly 528 // Nothing to do, but post a callback instead of calling directly
514 // to preserve the async style behavior to prevent bugs. 529 // to preserve the async style behavior to prevent bugs.
515 PostStoreUpdateResultForIds( 530 PostStoreUpdateResultForIds(
516 base::ThreadTaskRunnerHandle::Get(), state(), offline_ids, 531 base::ThreadTaskRunnerHandle::Get(), state(), offline_ids,
517 ItemActionStatus::NOT_FOUND /* will be ignored */, callback); 532 ItemActionStatus::NOT_FOUND /* will be ignored */, callback);
518 return; 533 return;
519 } 534 }
520 535
521 background_task_runner_->PostTask( 536 background_task_runner_->PostTask(
522 FROM_HERE, base::Bind(&RemoveOfflinePagesSync, offline_ids, db_.get(), 537 FROM_HERE, base::Bind(&RemoveOfflinePagesSync, offline_ids, db_.get(),
523 base::ThreadTaskRunnerHandle::Get(), callback)); 538 base::ThreadTaskRunnerHandle::Get(), callback));
524 } 539 }
525 540
526 void OfflinePageMetadataStoreSQL::Reset(const ResetCallback& callback) { 541 void OfflinePageMetadataStoreSQL::Reset(const ResetCallback& callback) {
527 if (!CheckDb(base::Bind(callback, false)))
528 return;
529
530 background_task_runner_->PostTask( 542 background_task_runner_->PostTask(
531 FROM_HERE, 543 FROM_HERE,
532 base::Bind(&ResetSync, db_.get(), db_file_path_, 544 base::Bind(&ResetSync, db_.get(), db_file_path_,
533 base::ThreadTaskRunnerHandle::Get(), 545 base::ThreadTaskRunnerHandle::Get(),
534 base::Bind(&OfflinePageMetadataStoreSQL::OnResetDone, 546 base::Bind(&OfflinePageMetadataStoreSQL::OnResetDone,
535 weak_ptr_factory_.GetWeakPtr(), callback))); 547 weak_ptr_factory_.GetWeakPtr(), callback)));
536 } 548 }
537 549
538 StoreState OfflinePageMetadataStoreSQL::state() const { 550 StoreState OfflinePageMetadataStoreSQL::state() const {
539 return state_; 551 return state_;
540 } 552 }
541 553
542 void OfflinePageMetadataStoreSQL::SetStateForTesting(StoreState state, 554 void OfflinePageMetadataStoreSQL::SetStateForTesting(StoreState state,
543 bool reset_db) { 555 bool reset_db) {
544 state_ = state; 556 state_ = state;
545 if (reset_db) 557 if (reset_db)
546 db_.reset(nullptr); 558 db_.reset(nullptr);
547 } 559 }
548 560
549 void OfflinePageMetadataStoreSQL::OpenConnection() { 561 void OfflinePageMetadataStoreSQL::OnOpenConnectionDone(
550 DCHECK(!db_); 562 const InitializeCallback& callback,
551 db_.reset(new sql::Connection()); 563 bool success) {
552 background_task_runner_->PostTask(
553 FROM_HERE,
554 base::Bind(&OpenConnectionSync, db_.get(),
555 base::ThreadTaskRunnerHandle::Get(), db_file_path_,
556 base::Bind(&OfflinePageMetadataStoreSQL::OnOpenConnectionDone,
557 weak_ptr_factory_.GetWeakPtr())));
558 }
559
560 void OfflinePageMetadataStoreSQL::OnOpenConnectionDone(StoreState state) {
561 DCHECK(db_.get()); 564 DCHECK(db_.get());
562 565 state_ = success ? StoreState::LOADED : StoreState::FAILED_LOADING;
563 state_ = state; 566 callback.Run(success);
564
565 // Unfortunately we were not able to open DB connection.
566 if (state != StoreState::LOADED)
567 db_.reset();
568
569 // TODO(fgorski): This might be a place to start store recovery. Alternatively
570 // that can be attempted in the OfflinePageModel.
571 } 567 }
572 568
573 void OfflinePageMetadataStoreSQL::OnResetDone(const ResetCallback& callback, 569 void OfflinePageMetadataStoreSQL::OnResetDone(const ResetCallback& callback,
574 StoreState state) { 570 bool success) {
575 OnOpenConnectionDone(state); 571 state_ = success ? StoreState::NOT_LOADED : StoreState::FAILED_RESET;
576 callback.Run(state == StoreState::LOADED); 572 db_.reset(nullptr);
jianli 2016/11/16 01:34:50 nit: do we really need nullptr?
fgorski 2016/11/16 19:10:13 Looks like we don't. I thought that this was C++17
573 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
574 base::Bind(callback, success));
577 } 575 }
578 576
579 bool OfflinePageMetadataStoreSQL::CheckDb(const base::Closure& callback) { 577 bool OfflinePageMetadataStoreSQL::CheckDb() {
580 if (!db_.get() || state_ != StoreState::LOADED) { 578 return db_ && state_ == StoreState::LOADED;
581 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
582 return false;
583 }
584 return true;
585 } 579 }
586 580
587 } // namespace offline_pages 581 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698