| Index: chrome/browser/sync/glue/typed_url_model_associator.cc
|
| diff --git a/chrome/browser/sync/glue/typed_url_model_associator.cc b/chrome/browser/sync/glue/typed_url_model_associator.cc
|
| index 5717b5123c1c3fc2622f17666c6c592aa2cba0a0..c6fe1583e6c2b0840f4619a8fc664239da264718 100644
|
| --- a/chrome/browser/sync/glue/typed_url_model_associator.cc
|
| +++ b/chrome/browser/sync/glue/typed_url_model_associator.cc
|
| @@ -9,6 +9,7 @@
|
|
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| +#include "base/metrics/histogram.h"
|
| #include "base/utf_string_conversions.h"
|
| #include "chrome/browser/history/history_backend.h"
|
| #include "chrome/browser/sync/api/sync_error.h"
|
| @@ -64,7 +65,9 @@ TypedUrlModelAssociator::TypedUrlModelAssociator(
|
| history_backend_(history_backend),
|
| expected_loop_(MessageLoop::current()),
|
| pending_abort_(false),
|
| - error_handler_(error_handler) {
|
| + error_handler_(error_handler),
|
| + num_db_accesses_(0),
|
| + num_db_errors_(0) {
|
| DCHECK(sync_service_);
|
| // history_backend_ may be null for unit tests (since it's not mockable).
|
| DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| @@ -73,13 +76,16 @@ TypedUrlModelAssociator::TypedUrlModelAssociator(
|
| TypedUrlModelAssociator::~TypedUrlModelAssociator() {}
|
|
|
|
|
| -// static
|
| bool TypedUrlModelAssociator::FixupURLAndGetVisits(
|
| history::HistoryBackend* backend,
|
| history::URLRow* url,
|
| history::VisitVector* visits) {
|
| - if (!backend->GetMostRecentVisitsForURL(url->id(), kMaxVisitsToFetch, visits))
|
| + ++num_db_accesses_;
|
| + if (!backend->GetMostRecentVisitsForURL(
|
| + url->id(), kMaxVisitsToFetch, visits)) {
|
| + ++num_db_errors_;
|
| return false;
|
| + }
|
|
|
| // Sometimes (due to a bug elsewhere in the history or sync code, or due to
|
| // a crash between adding a URL to the history database and updating the
|
| @@ -133,13 +139,33 @@ bool TypedUrlModelAssociator::ShouldIgnoreUrl(
|
| }
|
|
|
| SyncError TypedUrlModelAssociator::AssociateModels() {
|
| + ClearErrorStats();
|
| + SyncError error = DoAssociateModels();
|
| + UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlModelAssociationErrors",
|
| + GetErrorPercentage());
|
| + ClearErrorStats();
|
| + return error;
|
| +}
|
| +
|
| +void TypedUrlModelAssociator::ClearErrorStats() {
|
| + num_db_accesses_ = 0;
|
| + num_db_errors_ = 0;
|
| +}
|
| +
|
| +int TypedUrlModelAssociator::GetErrorPercentage() const {
|
| + return num_db_accesses_ ? (100 * num_db_errors_ / num_db_accesses_) : 0;
|
| +}
|
| +
|
| +SyncError TypedUrlModelAssociator::DoAssociateModels() {
|
| DVLOG(1) << "Associating TypedUrl Models";
|
| SyncError error;
|
| DCHECK(expected_loop_ == MessageLoop::current());
|
| if (IsAbortPending())
|
| return SyncError();
|
| history::URLRows typed_urls;
|
| + ++num_db_accesses_;
|
| if (!history_backend_->GetAllTypedURLs(&typed_urls)) {
|
| + ++num_db_errors_;
|
| return error_handler_->CreateAndUploadError(
|
| FROM_HERE,
|
| "Could not get the typed_url entries.",
|
| @@ -315,14 +341,11 @@ SyncError TypedUrlModelAssociator::AssociateModels() {
|
| // Update the local DB from the sync DB. Since we are doing our
|
| // initial model association, we don't want to remove any of the
|
| // existing visits (pass NULL as |visits_to_remove|).
|
| - error = UpdateFromSyncDB(filtered_url,
|
| - &new_visits,
|
| - NULL,
|
| - &updated_urls,
|
| - &new_urls);
|
| - if (error.IsSet()) {
|
| - return error;
|
| - }
|
| + UpdateFromSyncDB(filtered_url,
|
| + &new_visits,
|
| + NULL,
|
| + &updated_urls,
|
| + &new_urls);
|
| }
|
| }
|
|
|
| @@ -351,24 +374,17 @@ SyncError TypedUrlModelAssociator::AssociateModels() {
|
| // this is the only thread that writes to the database. We also don't have
|
| // to worry about the sync model getting out of sync, because changes are
|
| // propagated to the ChangeProcessor on this thread.
|
| - error = WriteToHistoryBackend(&new_urls, &updated_urls,
|
| - &new_visits, NULL);
|
| - if (error.IsSet()) {
|
| - return error;
|
| - }
|
| + WriteToHistoryBackend(&new_urls, &updated_urls, &new_visits, NULL);
|
| return error;
|
| }
|
|
|
| -SyncError TypedUrlModelAssociator::UpdateFromSyncDB(
|
| +void TypedUrlModelAssociator::UpdateFromSyncDB(
|
| const sync_pb::TypedUrlSpecifics& typed_url,
|
| TypedUrlVisitVector* visits_to_add,
|
| history::VisitVector* visits_to_remove,
|
| TypedUrlUpdateVector* updated_urls,
|
| history::URLRows* new_urls) {
|
| history::URLRow new_url(GURL(typed_url.url()));
|
| - visits_to_add->push_back(std::pair<GURL, std::vector<history::VisitInfo> >(
|
| - new_url.url(), std::vector<history::VisitInfo>()));
|
| -
|
| history::VisitVector existing_visits;
|
| bool existing_url = history_backend_->GetURL(new_url.url(), &new_url);
|
| if (existing_url) {
|
| @@ -377,11 +393,14 @@ SyncError TypedUrlModelAssociator::UpdateFromSyncDB(
|
| if (!FixupURLAndGetVisits(
|
| history_backend_, &new_url, &existing_visits)) {
|
| // Couldn't load the visits for this URL due to some kind of DB error.
|
| - // Just treat this URL as if it were not an existing URL.
|
| - LOG(ERROR) << "Could not load visits for url: " << new_url.url();
|
| - existing_url = false;
|
| + // Don't bother writing this URL to the history DB (if we ignore the
|
| + // error and continue, we might end up duplicating existing visits).
|
| + DLOG(ERROR) << "Could not load visits for url: " << new_url.url();
|
| + return;
|
| }
|
| }
|
| + visits_to_add->push_back(std::pair<GURL, std::vector<history::VisitInfo> >(
|
| + new_url.url(), std::vector<history::VisitInfo>()));
|
|
|
| // Update the URL with information from the typed URL.
|
| UpdateURLRowFromTypedUrlSpecifics(typed_url, &new_url);
|
| @@ -396,8 +415,6 @@ SyncError TypedUrlModelAssociator::UpdateFromSyncDB(
|
| } else {
|
| new_urls->push_back(new_url);
|
| }
|
| -
|
| - return SyncError();
|
| }
|
|
|
| sync_pb::TypedUrlSpecifics TypedUrlModelAssociator::FilterExpiredVisits(
|
| @@ -473,7 +490,7 @@ bool TypedUrlModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
|
| return true;
|
| }
|
|
|
| -SyncError TypedUrlModelAssociator::WriteToHistoryBackend(
|
| +void TypedUrlModelAssociator::WriteToHistoryBackend(
|
| const history::URLRows* new_urls,
|
| const TypedUrlUpdateVector* updated_urls,
|
| const TypedUrlVisitVector* new_visits,
|
| @@ -488,12 +505,13 @@ SyncError TypedUrlModelAssociator::WriteToHistoryBackend(
|
| // visit_count or typed_count values here, because either one (or both)
|
| // could be zero in the case of bookmarks, or in the case of a URL
|
| // transitioning from non-typed to typed as a result of this sync.
|
| + ++num_db_accesses_;
|
| if (!history_backend_->UpdateURL(url->first, url->second)) {
|
| - LOG(ERROR) << "Could not update page: " << url->second.url().spec();
|
| - return error_handler_->CreateAndUploadError(
|
| - FROM_HERE,
|
| - "UpdateURl() failed",
|
| - model_type());
|
| + // In the field we sometimes run into errors on specific URLs. It's OK
|
| + // to just continue on (we can try writing again on the next model
|
| + // association).
|
| + ++num_db_errors_;
|
| + DLOG(ERROR) << "Could not update page: " << url->second.url().spec();
|
| }
|
| }
|
| }
|
| @@ -503,28 +521,24 @@ SyncError TypedUrlModelAssociator::WriteToHistoryBackend(
|
| // If there are no visits to add, just skip this.
|
| if (visits->second.empty())
|
| continue;
|
| + ++num_db_accesses_;
|
| if (!history_backend_->AddVisits(visits->first, visits->second,
|
| history::SOURCE_SYNCED)) {
|
| - LOG(ERROR) << "Could not add visits.";
|
| - return error_handler_->CreateAndUploadError(
|
| - FROM_HERE,
|
| - "AddVisits() failed",
|
| - model_type());
|
| -
|
| + ++num_db_errors_;
|
| + DLOG(ERROR) << "Could not add visits.";
|
| }
|
| }
|
| }
|
| if (deleted_visits) {
|
| + ++num_db_accesses_;
|
| if (!history_backend_->RemoveVisits(*deleted_visits)) {
|
| - LOG(ERROR) << "Could not remove visits.";
|
| - return error_handler_->CreateAndUploadError(
|
| - FROM_HERE,
|
| - "RemoveVisits() failed",
|
| - model_type());
|
| -
|
| + ++num_db_errors_;
|
| + DLOG(ERROR) << "Could not remove visits.";
|
| + // This is bad news, since it means we may end up resurrecting history
|
| + // entries on the next reload. It's unavoidable so we'll just keep on
|
| + // syncing.
|
| }
|
| }
|
| - return SyncError();
|
| }
|
|
|
| // static
|
|
|