summaryrefslogtreecommitdiffstats
path: root/components/history
diff options
context:
space:
mode:
authorgangwu <gangwu@chromium.org>2015-12-15 15:00:15 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-15 23:01:12 +0000
commita9fc84392b6dd9d1ae1801c4f6b2334d4d1fad30 (patch)
tree478f2825eee3588e439f66f99cd9d0be3fc71854 /components/history
parent3baa84abc53467cc667243d1a45edc0a9a94662a (diff)
downloadchromium_src-a9fc84392b6dd9d1ae1801c4f6b2334d4d1fad30.zip
chromium_src-a9fc84392b6dd9d1ae1801c4f6b2334d4d1fad30.tar.gz
chromium_src-a9fc84392b6dd9d1ae1801c4f6b2334d4d1fad30.tar.bz2
Using TypedUrlSyncableService instead of
TypedUrlModelAssociator and TypedUrlChangeProcessor. And also fix some test issues because of this changes. BUG=77819,543722 Committed: https://crrev.com/0295776af08f6f03850492a70b60d52855a112dd Cr-Commit-Position: refs/heads/master@{#365199} Review URL: https://codereview.chromium.org/1454503002 Cr-Commit-Position: refs/heads/master@{#365368}
Diffstat (limited to 'components/history')
-rw-r--r--components/history/core/browser/BUILD.gn5
-rw-r--r--components/history/core/browser/history_backend.cc12
-rw-r--r--components/history/core/browser/history_service.h2
-rw-r--r--components/history/core/browser/typed_url_change_processor.cc356
-rw-r--r--components/history/core/browser/typed_url_change_processor.h137
-rw-r--r--components/history/core/browser/typed_url_data_type_controller.cc40
-rw-r--r--components/history/core/browser/typed_url_data_type_controller.h13
-rw-r--r--components/history/core/browser/typed_url_model_associator.cc862
-rw-r--r--components/history/core/browser/typed_url_model_associator.h208
-rw-r--r--components/history/core/browser/typed_url_model_associator_unittest.cc432
-rw-r--r--components/history/core/browser/typed_url_syncable_service.cc101
-rw-r--r--components/history/core/browser/typed_url_syncable_service.h31
-rw-r--r--components/history/core/browser/typed_url_syncable_service_unittest.cc11
13 files changed, 90 insertions, 2120 deletions
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn
index e894ec6..0d88839 100644
--- a/components/history/core/browser/BUILD.gn
+++ b/components/history/core/browser/BUILD.gn
@@ -62,12 +62,8 @@ static_library("browser") {
"top_sites_impl.cc",
"top_sites_impl.h",
"top_sites_observer.h",
- "typed_url_change_processor.cc",
- "typed_url_change_processor.h",
"typed_url_data_type_controller.cc",
"typed_url_data_type_controller.h",
- "typed_url_model_associator.cc",
- "typed_url_model_associator.h",
"typed_url_syncable_service.cc",
"typed_url_syncable_service.h",
"url_database.cc",
@@ -154,7 +150,6 @@ source_set("unit_tests") {
"top_sites_cache_unittest.cc",
"top_sites_database_unittest.cc",
"top_sites_impl_unittest.cc",
- "typed_url_model_associator_unittest.cc",
"typed_url_syncable_service_unittest.cc",
"url_database_unittest.cc",
"url_utils_unittest.cc",
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 0982fcd..0779add 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -2551,10 +2551,6 @@ void HistoryBackend::NotifyURLVisited(ui::PageTransition transition,
const URLRow& row,
const RedirectList& redirects,
base::Time visit_time) {
- if (typed_url_syncable_service_)
- typed_url_syncable_service_->OnURLVisited(this, transition, row, redirects,
- visit_time);
-
FOR_EACH_OBSERVER(HistoryBackendObserver, observers_,
OnURLVisited(this, transition, row, redirects, visit_time));
@@ -2563,9 +2559,6 @@ void HistoryBackend::NotifyURLVisited(ui::PageTransition transition,
}
void HistoryBackend::NotifyURLsModified(const URLRows& rows) {
- if (typed_url_syncable_service_)
- typed_url_syncable_service_->OnURLsModified(this, rows);
-
FOR_EACH_OBSERVER(HistoryBackendObserver, observers_,
OnURLsModified(this, rows));
@@ -2578,11 +2571,6 @@ void HistoryBackend::NotifyURLsDeleted(bool all_history,
const URLRows& rows,
const std::set<GURL>& favicon_urls) {
URLRows copied_rows(rows);
- if (typed_url_syncable_service_) {
- typed_url_syncable_service_->OnURLsDeleted(this, all_history, expired,
- copied_rows, favicon_urls);
- }
-
FOR_EACH_OBSERVER(
HistoryBackendObserver, observers_,
OnURLsDeleted(this, all_history, expired, copied_rows, favicon_urls));
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index aa36e9e..c535158 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -146,7 +146,7 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
// Returns a pointer to the TypedUrlSyncableService owned by HistoryBackend.
// This method should only be called from the history thread, because the
// returned service is intended to be accessed only via the history thread.
- TypedUrlSyncableService* GetTypedUrlSyncableService() const;
+ virtual TypedUrlSyncableService* GetTypedUrlSyncableService() const;
// KeyedService:
void Shutdown() override;
diff --git a/components/history/core/browser/typed_url_change_processor.cc b/components/history/core/browser/typed_url_change_processor.cc
deleted file mode 100644
index 4395e80..0000000
--- a/components/history/core/browser/typed_url_change_processor.cc
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/history/core/browser/typed_url_change_processor.h"
-
-#include "base/location.h"
-#include "base/metrics/histogram.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/thread_task_runner_handle.h"
-#include "components/history/core/browser/history_backend.h"
-#include "components/history/core/browser/typed_url_model_associator.h"
-#include "sync/internal_api/public/change_record.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
-#include "sync/syncable/entry.h" // TODO(tim): Investigating bug 121587.
-
-namespace browser_sync {
-
-// This is the threshold at which we start throttling sync updates for typed
-// URLs - any URLs with a typed_count >= this threshold will be throttled.
-static const int kTypedUrlVisitThrottleThreshold = 10;
-
-// This is the multiple we use when throttling sync updates. If the multiple is
-// N, we sync up every Nth update (i.e. when typed_count % N == 0).
-static const int kTypedUrlVisitThrottleMultiple = 10;
-
-TypedUrlChangeProcessor::TypedUrlChangeProcessor(
- TypedUrlModelAssociator* model_associator,
- history::HistoryBackend* history_backend,
- sync_driver::DataTypeErrorHandler* error_handler,
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread)
- : sync_driver::ChangeProcessor(error_handler),
- model_associator_(model_associator),
- history_backend_(history_backend),
- ui_thread_(ui_thread),
- backend_thread_(base::ThreadTaskRunnerHandle::Get()),
- disconnected_(false),
- history_backend_observer_(this) {
- DCHECK(model_associator);
- DCHECK(history_backend);
- DCHECK(error_handler);
-}
-
-TypedUrlChangeProcessor::~TypedUrlChangeProcessor() {
- DCHECK(backend_thread_->BelongsToCurrentThread());
- DCHECK(history_backend_);
- history_backend_->RemoveObserver(this);
-}
-
-void TypedUrlChangeProcessor::OnURLVisited(
- history::HistoryBackend* history_backend,
- ui::PageTransition transition,
- const history::URLRow& row,
- const history::RedirectList& redirects,
- base::Time visit_time) {
- DCHECK(backend_thread_->BelongsToCurrentThread());
-
- base::AutoLock al(disconnect_lock_);
- if (disconnected_)
- return;
-
- DVLOG(1) << "Observed typed_url change.";
- if (ShouldSyncVisit(row.typed_count(), transition)) {
- VisitsToSync visits_to_sync;
- if (FixupURLAndGetVisitsToSync(row, &visits_to_sync)) {
- syncer::WriteTransaction trans(FROM_HERE, share_handle());
- CreateOrUpdateSyncNode(&trans, visits_to_sync.row, visits_to_sync.visits);
- }
- }
- UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlChangeProcessorErrors",
- model_associator_->GetErrorPercentage());
-}
-
-void TypedUrlChangeProcessor::OnURLsModified(
- history::HistoryBackend* history_backend,
- const history::URLRows& changed_urls) {
- DCHECK(backend_thread_->BelongsToCurrentThread());
-
- base::AutoLock al(disconnect_lock_);
- if (disconnected_)
- return;
-
- std::vector<VisitsToSync> visits_to_sync_vector;
-
- DVLOG(1) << "Observed typed_url change.";
- for (const auto& row : changed_urls) {
- if (row.typed_count() >= 0) {
- VisitsToSync visits_to_sync;
- if (FixupURLAndGetVisitsToSync(row, &visits_to_sync)) {
- visits_to_sync_vector.push_back(visits_to_sync);
- }
- }
- }
-
- if (!visits_to_sync_vector.empty()) {
- syncer::WriteTransaction trans(FROM_HERE, share_handle());
- for (const auto& visits_to_sync : visits_to_sync_vector) {
- // If there were any errors updating the sync node, just ignore them and
- // continue on to process the next URL.
- CreateOrUpdateSyncNode(&trans, visits_to_sync.row, visits_to_sync.visits);
- }
- }
-
- UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlChangeProcessorErrors",
- model_associator_->GetErrorPercentage());
-}
-
-void TypedUrlChangeProcessor::OnURLsDeleted(
- history::HistoryBackend* history_backend,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
- DCHECK(backend_thread_->BelongsToCurrentThread());
-
- base::AutoLock al(disconnect_lock_);
- if (disconnected_)
- return;
-
- DVLOG(1) << "Observed typed_url change.";
-
- syncer::WriteTransaction trans(FROM_HERE, share_handle());
-
- // Ignore archivals (we don't want to sync them as deletions, to avoid
- // extra traffic up to the server, and also to make sure that a client with
- // a bad clock setting won't go on an archival rampage and delete all
- // history from every client). The server will gracefully age out the sync DB
- // entries when they've been idle for long enough.
- if (expired)
- return;
-
- if (all_history) {
- if (!model_associator_->DeleteAllNodes(&trans)) {
- syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
- "Failed to delete local nodes.",
- syncer::TYPED_URLS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
- return;
- }
- } else {
- for (const auto& row : deleted_rows) {
- syncer::WriteNode sync_node(&trans);
- // The deleted URL could have been non-typed, so it might not be found
- // in the sync DB.
- if (sync_node.InitByClientTagLookup(syncer::TYPED_URLS,
- row.url().spec()) ==
- syncer::BaseNode::INIT_OK) {
- sync_node.Tombstone();
- }
- }
- }
- UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlChangeProcessorErrors",
- model_associator_->GetErrorPercentage());
-}
-
-TypedUrlChangeProcessor::VisitsToSync::VisitsToSync() {}
-
-TypedUrlChangeProcessor::VisitsToSync::~VisitsToSync() {}
-
-bool TypedUrlChangeProcessor::FixupURLAndGetVisitsToSync(
- const history::URLRow& url,
- VisitsToSync* visits_to_sync) {
- DCHECK_GE(url.typed_count(), 0);
-
- // Get the visits for this node.
- visits_to_sync->row = url;
- if (!model_associator_->FixupURLAndGetVisits(&visits_to_sync->row,
- &visits_to_sync->visits)) {
- DLOG(ERROR) << "Could not load visits for url: " << url.url();
- return false;
- }
-
- if (std::find_if(visits_to_sync->visits.begin(), visits_to_sync->visits.end(),
- [](const history::VisitRow& visit) {
- return ui::PageTransitionCoreTypeIs(
- visit.transition, ui::PAGE_TRANSITION_TYPED);
- }) == visits_to_sync->visits.end()) {
- // This URL has no TYPED visits, don't sync it.
- return false;
- }
-
- if (model_associator_->ShouldIgnoreUrl(visits_to_sync->row.url()))
- return false;
-
- return true;
-}
-
-void TypedUrlChangeProcessor::CreateOrUpdateSyncNode(
- syncer::WriteTransaction* trans,
- const history::URLRow& url,
- const history::VisitVector& visit_vector) {
- DCHECK_GE(url.typed_count(), 0);
- DCHECK(!visit_vector.empty());
-
- std::string tag = url.url().spec();
- syncer::WriteNode update_node(trans);
- syncer::BaseNode::InitByLookupResult result =
- update_node.InitByClientTagLookup(syncer::TYPED_URLS, tag);
- if (result == syncer::BaseNode::INIT_OK) {
- model_associator_->WriteToSyncNode(url, visit_vector, &update_node);
- } else if (result == syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY) {
- syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
- "Failed to decrypt.", syncer::TYPED_URLS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
- return;
- } else {
- syncer::WriteNode create_node(trans);
- syncer::WriteNode::InitUniqueByCreationResult result =
- create_node.InitUniqueByCreation(syncer::TYPED_URLS, tag);
- if (result != syncer::WriteNode::INIT_SUCCESS) {
- syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
- "Failed to create sync node", syncer::TYPED_URLS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
- return;
- }
-
- create_node.SetTitle(tag);
- model_associator_->WriteToSyncNode(url, visit_vector, &create_node);
- }
-}
-
-bool TypedUrlChangeProcessor::ShouldSyncVisit(int typed_count,
- ui::PageTransition transition) {
- // Just use an ad-hoc criteria to determine whether to ignore this
- // notification. For most users, the distribution of visits is roughly a bell
- // curve with a long tail - there are lots of URLs with < 5 visits so we want
- // to make sure we sync up every visit to ensure the proper ordering of
- // suggestions. But there are relatively few URLs with > 10 visits, and those
- // tend to be more broadly distributed such that there's no need to sync up
- // every visit to preserve their relative ordering.
- return (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) &&
- typed_count >= 0 &&
- (typed_count < kTypedUrlVisitThrottleThreshold ||
- (typed_count % kTypedUrlVisitThrottleMultiple) == 0));
-}
-
-void TypedUrlChangeProcessor::ApplyChangesFromSyncModel(
- const syncer::BaseTransaction* trans,
- int64 model_version,
- const syncer::ImmutableChangeRecordList& changes) {
- DCHECK(backend_thread_->BelongsToCurrentThread());
-
- base::AutoLock al(disconnect_lock_);
- if (disconnected_)
- return;
-
- syncer::ReadNode typed_url_root(trans);
- if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) !=
- syncer::BaseNode::INIT_OK) {
- syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
- "Failed to init type root.", syncer::TYPED_URLS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
- return;
- }
-
- DCHECK(pending_new_urls_.empty() && pending_new_visits_.empty() &&
- pending_deleted_visits_.empty() && pending_updated_urls_.empty() &&
- pending_deleted_urls_.empty());
-
- for (syncer::ChangeRecordList::const_iterator it = changes.Get().begin();
- it != changes.Get().end(); ++it) {
- if (syncer::ChangeRecord::ACTION_DELETE == it->action) {
- DCHECK(it->specifics.has_typed_url())
- << "Typed URL delete change does not have necessary specifics.";
- GURL url(it->specifics.typed_url().url());
- pending_deleted_urls_.push_back(url);
- continue;
- }
-
- syncer::ReadNode sync_node(trans);
- if (sync_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
- syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
- "Failed to init sync node.", syncer::TYPED_URLS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
- return;
- }
-
- DCHECK(syncer::TYPED_URLS == sync_node.GetModelType());
-
- const sync_pb::TypedUrlSpecifics& typed_url(
- sync_node.GetTypedUrlSpecifics());
- DCHECK(typed_url.visits_size());
-
- if (model_associator_->ShouldIgnoreUrl(GURL(typed_url.url())))
- continue;
-
- sync_pb::TypedUrlSpecifics filtered_url =
- model_associator_->FilterExpiredVisits(typed_url);
- if (!filtered_url.visits_size()) {
- continue;
- }
-
- model_associator_->UpdateFromSyncDB(
- filtered_url, &pending_new_visits_, &pending_deleted_visits_,
- &pending_updated_urls_, &pending_new_urls_);
- }
-}
-
-void TypedUrlChangeProcessor::CommitChangesFromSyncModel() {
- DCHECK(backend_thread_->BelongsToCurrentThread());
-
- base::AutoLock al(disconnect_lock_);
- if (disconnected_)
- return;
-
- // Make sure we stop listening for changes while we're modifying the backend,
- // so we don't try to re-apply these changes to the sync DB.
- ScopedStopObserving<TypedUrlChangeProcessor> stop_observing(this);
- if (!pending_deleted_urls_.empty())
- history_backend_->DeleteURLs(pending_deleted_urls_);
-
- model_associator_->WriteToHistoryBackend(
- &pending_new_urls_, &pending_updated_urls_, &pending_new_visits_,
- &pending_deleted_visits_);
-
- pending_new_urls_.clear();
- pending_updated_urls_.clear();
- pending_new_visits_.clear();
- pending_deleted_visits_.clear();
- pending_deleted_urls_.clear();
- UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlChangeProcessorErrors",
- model_associator_->GetErrorPercentage());
-}
-
-void TypedUrlChangeProcessor::Disconnect() {
- base::AutoLock al(disconnect_lock_);
- disconnected_ = true;
-}
-
-void TypedUrlChangeProcessor::StartImpl() {
- DCHECK(history_backend_);
- DCHECK(backend_thread_);
- DCHECK(ui_thread_->BelongsToCurrentThread());
- backend_thread_->PostTask(FROM_HERE,
- base::Bind(&TypedUrlChangeProcessor::StartObserving,
- base::Unretained(this)));
-}
-
-void TypedUrlChangeProcessor::StartObserving() {
- DCHECK(backend_thread_->BelongsToCurrentThread());
- DCHECK(history_backend_);
- history_backend_observer_.Add(history_backend_);
-}
-
-void TypedUrlChangeProcessor::StopObserving() {
- DCHECK(backend_thread_->BelongsToCurrentThread());
- DCHECK(history_backend_);
- history_backend_observer_.RemoveAll();
-}
-
-} // namespace browser_sync
diff --git a/components/history/core/browser/typed_url_change_processor.h b/components/history/core/browser/typed_url_change_processor.h
deleted file mode 100644
index e397d30..0000000
--- a/components/history/core/browser/typed_url_change_processor.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_CHANGE_PROCESSOR_H_
-#define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_CHANGE_PROCESSOR_H_
-
-#include "components/sync_driver/change_processor.h"
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/scoped_observer.h"
-#include "components/history/core/browser/history_backend_observer.h"
-#include "components/history/core/browser/typed_url_model_associator.h"
-#include "components/sync_driver/data_type_error_handler.h"
-
-namespace base {
-class MessageLoop;
-}
-
-namespace history {
-class HistoryBackend;
-class URLRow;
-};
-
-namespace browser_sync {
-
-class DataTypeErrorHandler;
-
-// This class is responsible for taking changes from the history backend and
-// applying them to the sync API 'syncable' model, and vice versa. All
-// operations and use of this class are from the UI thread.
-class TypedUrlChangeProcessor : public sync_driver::ChangeProcessor,
- public history::HistoryBackendObserver {
- public:
- TypedUrlChangeProcessor(
- TypedUrlModelAssociator* model_associator,
- history::HistoryBackend* history_backend,
- sync_driver::DataTypeErrorHandler* error_handler,
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread);
- ~TypedUrlChangeProcessor() override;
-
- // sync API model -> WebDataService change application.
- void ApplyChangesFromSyncModel(
- const syncer::BaseTransaction* trans,
- int64 model_version,
- const syncer::ImmutableChangeRecordList& changes) override;
-
- // Commit changes here, after we've released the transaction lock to avoid
- // jank.
- void CommitChangesFromSyncModel() override;
-
- // Stop processing changes and wait for being destroyed.
- void Disconnect();
-
- protected:
- void StartImpl() override;
-
- private:
- friend class ScopedStopObserving<TypedUrlChangeProcessor>;
- void StartObserving();
- void StopObserving();
-
- // history::HistoryBackendObserver:
- void OnURLVisited(history::HistoryBackend* history_backend,
- ui::PageTransition transition,
- const history::URLRow& row,
- const history::RedirectList& redirects,
- base::Time visit_time) override;
- void OnURLsModified(history::HistoryBackend* history_backend,
- const history::URLRows& changed_urls) override;
- void OnURLsDeleted(history::HistoryBackend* history_backend,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
-
- // Returns true if the caller should sync as a result of the passed visit
- // notification. We use this to throttle the number of sync changes we send
- // to the server so we don't hit the server for every
- // single typed URL visit.
- bool ShouldSyncVisit(int typed_count, ui::PageTransition transition);
-
- // This struct is used to return result from FixupURLAndGetVisitsToSync
- // function below.
- struct VisitsToSync {
- VisitsToSync();
- ~VisitsToSync();
-
- history::URLRow row;
- history::VisitVector visits;
- };
-
- // Utility function that fixes the URL and retrieves visits to be used to
- // update sync node for the given |url|. Returns false if the data can't be
- // retrieved from History backend or if there are no typed visits to sync.
- bool FixupURLAndGetVisitsToSync(const history::URLRow& row,
- VisitsToSync* visits_to_sync);
-
- // Utility routine that either updates an existing sync node or creates a
- // new one for the passed |typed_url| if one does not already exist. Returns
- // false and sets an unrecoverable error if the operation failed.
- void CreateOrUpdateSyncNode(syncer::WriteTransaction* transaction,
- const history::URLRow& typed_url,
- const history::VisitVector& visit_vector);
-
- // The two models should be associated according to this ModelAssociator.
- TypedUrlModelAssociator* model_associator_;
-
- // The model we are processing changes from. This is owned by the
- // WebDataService which is kept alive by our data type controller
- // holding a reference.
- history::HistoryBackend* history_backend_;
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
- scoped_refptr<base::SingleThreadTaskRunner> backend_thread_;
-
- // The set of pending changes that will be written out on the next
- // CommitChangesFromSyncModel() call.
- history::URLRows pending_new_urls_;
- history::URLRows pending_updated_urls_;
- std::vector<GURL> pending_deleted_urls_;
- TypedUrlModelAssociator::TypedUrlVisitVector pending_new_visits_;
- history::VisitVector pending_deleted_visits_;
-
- bool disconnected_;
- base::Lock disconnect_lock_;
-
- ScopedObserver<history::HistoryBackend, history::HistoryBackendObserver>
- history_backend_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(TypedUrlChangeProcessor);
-};
-
-} // namespace browser_sync
-
-#endif // COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_CHANGE_PROCESSOR_H_
diff --git a/components/history/core/browser/typed_url_data_type_controller.cc b/components/history/core/browser/typed_url_data_type_controller.cc
index 717fbef..462569f 100644
--- a/components/history/core/browser/typed_url_data_type_controller.cc
+++ b/components/history/core/browser/typed_url_data_type_controller.cc
@@ -10,7 +10,6 @@
#include "base/prefs/pref_service.h"
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/typed_url_change_processor.h"
#include "components/sync_driver/sync_client.h"
namespace browser_sync {
@@ -57,9 +56,10 @@ TypedUrlDataTypeController::TypedUrlDataTypeController(
const base::Closure& error_callback,
sync_driver::SyncClient* sync_client,
const char* history_disabled_pref_name)
- : NonFrontendDataTypeController(ui_thread, error_callback, sync_client),
+ : NonUIDataTypeController(ui_thread, error_callback, sync_client),
history_disabled_pref_name_(history_disabled_pref_name),
- backend_(NULL) {
+ backend_(NULL),
+ sync_client_(sync_client) {
pref_registrar_.Init(sync_client->GetPrefService());
pref_registrar_.Add(
history_disabled_pref_name_,
@@ -78,7 +78,7 @@ syncer::ModelSafeGroup TypedUrlDataTypeController::model_safe_group() const {
bool TypedUrlDataTypeController::ReadyForStart() const {
DCHECK(ui_thread()->BelongsToCurrentThread());
- return !sync_client()->GetPrefService()->GetBoolean(
+ return !sync_client_->GetPrefService()->GetBoolean(
history_disabled_pref_name_);
}
@@ -89,16 +89,18 @@ void TypedUrlDataTypeController::SetBackend(history::HistoryBackend* backend) {
void TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged() {
DCHECK(ui_thread()->BelongsToCurrentThread());
- if (sync_client()->GetPrefService()->GetBoolean(
- history_disabled_pref_name_)) {
+ if (sync_client_->GetPrefService()->GetBoolean(history_disabled_pref_name_)) {
// We've turned off history persistence, so if we are running,
// generate an unrecoverable error. This can be fixed by restarting
// Chrome (on restart, typed urls will not be a registered type).
if (state() != NOT_RUNNING && state() != STOPPING) {
- syncer::SyncError error(
- FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
- "History saving is now disabled by policy.", syncer::TYPED_URLS);
- DisableImpl(error);
+ PostTaskOnBackendThread(
+ FROM_HERE,
+ base::Bind(&DataTypeController::OnSingleDataTypeUnrecoverableError,
+ this,
+ syncer::SyncError(
+ FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
+ "History saving is now disabled by policy.", type())));
}
}
}
@@ -107,7 +109,7 @@ bool TypedUrlDataTypeController::PostTaskOnBackendThread(
const tracked_objects::Location& from_here,
const base::Closure& task) {
DCHECK(ui_thread()->BelongsToCurrentThread());
- history::HistoryService* history = sync_client()->GetHistoryService();
+ history::HistoryService* history = sync_client_->GetHistoryService();
if (history) {
history->ScheduleDBTask(scoped_ptr<history::HistoryDBTask>(
new RunTaskOnHistoryThread(task, this)),
@@ -120,22 +122,6 @@ bool TypedUrlDataTypeController::PostTaskOnBackendThread(
}
}
-sync_driver::SyncApiComponentFactory::SyncComponents
-TypedUrlDataTypeController::CreateSyncComponents() {
- DCHECK(!ui_thread()->BelongsToCurrentThread());
- DCHECK_EQ(state(), ASSOCIATING);
- DCHECK(backend_);
- return sync_client()
- ->GetSyncApiComponentFactory()
- ->CreateTypedUrlSyncComponents(sync_client()->GetSyncService(), backend_,
- this);
-}
-
-void TypedUrlDataTypeController::DisconnectProcessor(
- sync_driver::ChangeProcessor* processor) {
- static_cast<TypedUrlChangeProcessor*>(processor)->Disconnect();
-}
-
TypedUrlDataTypeController::~TypedUrlDataTypeController() {}
} // namespace browser_sync
diff --git a/components/history/core/browser/typed_url_data_type_controller.h b/components/history/core/browser/typed_url_data_type_controller.h
index ab0e46b..58c4e8d 100644
--- a/components/history/core/browser/typed_url_data_type_controller.h
+++ b/components/history/core/browser/typed_url_data_type_controller.h
@@ -12,7 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/prefs/pref_change_registrar.h"
#include "base/task/cancelable_task_tracker.h"
-#include "components/sync_driver/non_frontend_data_type_controller.h"
+#include "components/sync_driver/non_ui_data_type_controller.h"
#include "components/sync_driver/sync_api_component_factory.h"
namespace history {
@@ -24,7 +24,7 @@ namespace browser_sync {
class ControlTask;
// A class that manages the startup and shutdown of typed_url sync.
-class TypedUrlDataTypeController : public NonFrontendDataTypeController {
+class TypedUrlDataTypeController : public sync_driver::NonUIDataTypeController {
public:
explicit TypedUrlDataTypeController(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
@@ -32,7 +32,7 @@ class TypedUrlDataTypeController : public NonFrontendDataTypeController {
sync_driver::SyncClient* sync_client,
const char* history_disabled_pref_name);
- // NonFrontendDataTypeController implementation
+ // NonUIDataTypeController implementation
syncer::ModelType type() const override;
syncer::ModelSafeGroup model_safe_group() const override;
bool ReadyForStart() const override;
@@ -42,12 +42,9 @@ class TypedUrlDataTypeController : public NonFrontendDataTypeController {
void SetBackend(history::HistoryBackend* backend);
protected:
- // NonFrontendDataTypeController interface.
+ // NonUIDataTypeController interface.
bool PostTaskOnBackendThread(const tracked_objects::Location& from_here,
const base::Closure& task) override;
- sync_driver::SyncApiComponentFactory::SyncComponents CreateSyncComponents()
- override;
- void DisconnectProcessor(sync_driver::ChangeProcessor* processor) override;
private:
~TypedUrlDataTypeController() override;
@@ -64,6 +61,8 @@ class TypedUrlDataTypeController : public NonFrontendDataTypeController {
// thread.
base::CancelableTaskTracker task_tracker_;
+ sync_driver::SyncClient* const sync_client_;
+
DISALLOW_COPY_AND_ASSIGN(TypedUrlDataTypeController);
};
diff --git a/components/history/core/browser/typed_url_model_associator.cc b/components/history/core/browser/typed_url_model_associator.cc
deleted file mode 100644
index 31a3979..0000000
--- a/components/history/core/browser/typed_url_model_associator.cc
+++ /dev/null
@@ -1,862 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/history/core/browser/typed_url_model_associator.h"
-
-#include <algorithm>
-#include <set>
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/history/core/browser/history_backend.h"
-#include "components/sync_driver/sync_service.h"
-#include "net/base/net_util.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
-
-namespace browser_sync {
-
-// The server backend can't handle arbitrarily large node sizes, so to keep
-// the size under control we limit the visit array.
-static const int kMaxTypedUrlVisits = 100;
-
-// There's no limit on how many visits the history DB could have for a given
-// typed URL, so we limit how many we fetch from the DB to avoid crashes due to
-// running out of memory (http://crbug.com/89793). This value is different
-// from kMaxTypedUrlVisits, as some of the visits fetched from the DB may be
-// RELOAD visits, which will be stripped.
-static const int kMaxVisitsToFetch = 1000;
-
-static bool CheckVisitOrdering(const history::VisitVector& visits) {
- int64 previous_visit_time = 0;
- for (history::VisitVector::const_iterator visit = visits.begin();
- visit != visits.end(); ++visit) {
- if (visit != visits.begin()) {
- // We allow duplicate visits here - they shouldn't really be allowed, but
- // they still seem to show up sometimes and we haven't figured out the
- // source, so we just log an error instead of failing an assertion.
- // (http://crbug.com/91473).
- if (previous_visit_time == visit->visit_time.ToInternalValue())
- DVLOG(1) << "Duplicate visit time encountered";
- else if (previous_visit_time > visit->visit_time.ToInternalValue())
- return false;
- }
-
- previous_visit_time = visit->visit_time.ToInternalValue();
- }
- return true;
-}
-
-TypedUrlModelAssociator::TypedUrlModelAssociator(
- sync_driver::SyncService* sync_service,
- history::HistoryBackend* history_backend,
- sync_driver::DataTypeErrorHandler* error_handler)
- : sync_service_(sync_service),
- history_backend_(history_backend),
- expected_loop_(base::MessageLoop::current()),
- abort_requested_(false),
- 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).
-}
-
-TypedUrlModelAssociator::~TypedUrlModelAssociator() {}
-
-
-bool TypedUrlModelAssociator::FixupURLAndGetVisits(
- history::URLRow* url,
- history::VisitVector* visits) {
- ++num_db_accesses_;
- CHECK(history_backend_);
- if (!history_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
- // visit DB) the visit vector for a URL can be empty. If this happens, just
- // create a new visit whose timestamp is the same as the last_visit time.
- // This is a workaround for http://crbug.com/84258.
- if (visits->empty()) {
- DVLOG(1) << "Found empty visits for URL: " << url->url();
-
- if (url->last_visit().is_null()) {
- // If modified URL is bookmarked, history backend treats it as modified
- // even if all its visits are deleted. Return false to stop further
- // processing because sync expects valid visit time for modified entry.
- return false;
- }
-
- history::VisitRow visit(
- url->id(), url->last_visit(), 0, ui::PAGE_TRANSITION_TYPED, 0);
- visits->push_back(visit);
- }
-
- // GetMostRecentVisitsForURL() returns the data in the opposite order that
- // we need it, so reverse it.
- std::reverse(visits->begin(), visits->end());
-
- // Sometimes, the last_visit field in the URL doesn't match the timestamp of
- // the last visit in our visit array (they come from different tables, so
- // crashes/bugs can cause them to mismatch), so just set it here.
- url->set_last_visit(visits->back().visit_time);
- DCHECK(CheckVisitOrdering(*visits));
- return true;
-}
-
-bool TypedUrlModelAssociator::ShouldIgnoreUrl(const GURL& url) {
- // Ignore empty URLs. Not sure how this can happen (maybe import from other
- // busted browsers, or misuse of the history API, or just plain bugs) but we
- // can't deal with them.
- if (url.spec().empty())
- return true;
-
- // Ignore local file URLs.
- if (url.SchemeIsFile())
- return true;
-
- // Ignore localhost URLs.
- if (net::IsLocalhost(url.host()))
- return true;
-
- return false;
-}
-
-bool TypedUrlModelAssociator::ShouldIgnoreVisits(
- const history::VisitVector& visits) {
- // We ignore URLs that were imported, but have never been visited by
- // chromium.
- static const int kLastImportedSource = history::SOURCE_EXTENSION;
- history::VisitSourceMap map;
- if (!history_backend_->GetVisitsSource(visits, &map))
- return false; // If we can't read the visit, assume it's not imported.
-
- // Walk the list of visits and look for a non-imported item.
- for (history::VisitVector::const_iterator it = visits.begin();
- it != visits.end(); ++it) {
- if (map.count(it->visit_id) == 0 ||
- map[it->visit_id] <= kLastImportedSource) {
- return false;
- }
- }
- // We only saw imported visits, so tell the caller to ignore them.
- return true;
-}
-
-syncer::SyncError TypedUrlModelAssociator::AssociateModels(
- syncer::SyncMergeResult* local_merge_result,
- syncer::SyncMergeResult* syncer_merge_result) {
- ClearErrorStats();
- syncer::SyncError error =
- DoAssociateModels(local_merge_result, syncer_merge_result);
- 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;
-}
-
-syncer::SyncError TypedUrlModelAssociator::DoAssociateModels(
- syncer::SyncMergeResult* local_merge_result,
- syncer::SyncMergeResult* syncer_merge_result) {
- DVLOG(1) << "Associating TypedUrl Models";
- DCHECK(expected_loop_ == base::MessageLoop::current());
-
- history::URLRows typed_urls;
- ++num_db_accesses_;
- bool query_succeeded =
- history_backend_ && history_backend_->GetAllTypedURLs(&typed_urls);
-
- history::URLRows new_urls;
- history::URLRows updated_urls;
- TypedUrlVisitVector new_visits;
- {
- base::AutoLock au(abort_lock_);
- if (abort_requested_) {
- return syncer::SyncError(FROM_HERE,
- syncer::SyncError::DATATYPE_ERROR,
- "Association was aborted.",
- model_type());
- }
-
- // Must lock and check first to make sure |error_handler_| is valid.
- if (!query_succeeded) {
- ++num_db_errors_;
- return error_handler_->CreateAndUploadError(
- FROM_HERE,
- "Could not get the typed_url entries.",
- model_type());
- }
- local_merge_result->set_num_items_before_association(typed_urls.size());
-
- // Get all the visits.
- std::map<history::URLID, history::VisitVector> visit_vectors;
- history::URLRows::iterator new_end = typed_urls.end();
- for (history::URLRows::iterator ix = typed_urls.begin();
- ix != new_end;) {
- DCHECK_EQ(0U, visit_vectors.count(ix->id()));
- if (!FixupURLAndGetVisits(&(*ix), &(visit_vectors[ix->id()])) ||
- ShouldIgnoreUrl(ix->url()) ||
- ShouldIgnoreVisits(visit_vectors[ix->id()])) {
- // Ignore this URL if we couldn't load the visits or if there's some
- // other problem with it (it was empty, or imported and never visited).
- --new_end;
- if (ix != new_end)
- *ix = *new_end;
- } else {
- ++ix;
- }
- }
- typed_urls.erase(new_end, typed_urls.end());
-
- syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
- syncer::ReadNode typed_url_root(&trans);
- if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) !=
- syncer::BaseNode::INIT_OK) {
- return error_handler_->CreateAndUploadError(
- FROM_HERE,
- "Server did not create the top-level typed_url node. We "
- "might be running against an out-of-date server.",
- model_type());
- }
- syncer_merge_result->set_num_items_before_association(
- typed_url_root.GetTotalNodeCount());
-
- std::set<std::string> current_urls;
- for (history::URLRows::iterator ix = typed_urls.begin();
- ix != typed_urls.end(); ++ix) {
- std::string tag = ix->url().spec();
- // Empty URLs should be filtered out by ShouldIgnoreUrl() previously.
- DCHECK(!tag.empty());
- history::VisitVector& visits = visit_vectors[ix->id()];
-
- syncer::ReadNode node(&trans);
- if (node.InitByClientTagLookup(syncer::TYPED_URLS, tag) ==
- syncer::BaseNode::INIT_OK) {
- // Same URL exists in sync data and in history data - compare the
- // entries to see if there's any difference.
- sync_pb::TypedUrlSpecifics typed_url(
- FilterExpiredVisits(node.GetTypedUrlSpecifics()));
- DCHECK_EQ(tag, typed_url.url());
-
- // Initialize fields in |new_url| to the same values as the fields in
- // the existing URLRow in the history DB. This is needed because we
- // overwrite the existing value below in WriteToHistoryBackend(), but
- // some of the values in that structure are not synced (like
- // typed_count).
- history::URLRow new_url(*ix);
-
- std::vector<history::VisitInfo> added_visits;
- MergeResult difference =
- MergeUrls(typed_url, *ix, &visits, &new_url, &added_visits);
- if (difference & DIFF_UPDATE_NODE) {
- syncer::WriteNode write_node(&trans);
- if (write_node.InitByClientTagLookup(syncer::TYPED_URLS, tag) !=
- syncer::BaseNode::INIT_OK) {
- return error_handler_->CreateAndUploadError(
- FROM_HERE,
- "Failed to edit typed_url sync node.",
- model_type());
- }
- // We don't want to resurrect old visits that have been aged out by
- // other clients, so remove all visits that are older than the
- // earliest existing visit in the sync node.
- if (typed_url.visits_size() > 0) {
- base::Time earliest_visit =
- base::Time::FromInternalValue(typed_url.visits(0));
- for (history::VisitVector::iterator it = visits.begin();
- it != visits.end() && it->visit_time < earliest_visit; ) {
- it = visits.erase(it);
- }
- // Should never be possible to delete all the items, since the
- // visit vector contains all the items in typed_url.visits.
- DCHECK_GT(visits.size(), 0u);
- }
- DCHECK_EQ(new_url.last_visit().ToInternalValue(),
- visits.back().visit_time.ToInternalValue());
- WriteToSyncNode(new_url, visits, &write_node);
- syncer_merge_result->set_num_items_modified(
- syncer_merge_result->num_items_modified() + 1);
- }
- if (difference & DIFF_LOCAL_ROW_CHANGED) {
- DCHECK_EQ(ix->id(), new_url.id());
- updated_urls.push_back(new_url);
- }
- if (difference & DIFF_LOCAL_VISITS_ADDED) {
- new_visits.push_back(
- std::pair<GURL, std::vector<history::VisitInfo> >(ix->url(),
- added_visits));
- }
- } else {
- // Sync has never seen this URL before.
- syncer::WriteNode node(&trans);
- syncer::WriteNode::InitUniqueByCreationResult result =
- node.InitUniqueByCreation(syncer::TYPED_URLS, tag);
- if (result != syncer::WriteNode::INIT_SUCCESS) {
- return error_handler_->CreateAndUploadError(
- FROM_HERE,
- "Failed to create typed_url sync node: " + tag,
- model_type());
- }
-
- node.SetTitle(tag);
- WriteToSyncNode(*ix, visits, &node);
- syncer_merge_result->set_num_items_added(
- syncer_merge_result->num_items_added() + 1);
- }
-
- current_urls.insert(tag);
- }
-
- // Now walk the sync nodes and detect any URLs that exist there, but not in
- // the history DB, so we can add them to our local history DB.
- std::vector<int64> obsolete_nodes;
- std::vector<int64> sync_ids;
- typed_url_root.GetChildIds(&sync_ids);
-
- for (std::vector<int64>::const_iterator it = sync_ids.begin();
- it != sync_ids.end(); ++it) {
- syncer::ReadNode sync_child_node(&trans);
- if (sync_child_node.InitByIdLookup(*it) != syncer::BaseNode::INIT_OK) {
- return error_handler_->CreateAndUploadError(
- FROM_HERE,
- "Failed to fetch child node.",
- model_type());
- }
- const sync_pb::TypedUrlSpecifics& typed_url(
- sync_child_node.GetTypedUrlSpecifics());
-
- // Ignore old sync nodes that don't have any transition data stored with
- // them, or transition data that does not match the visit data (will be
- // deleted below).
- if (typed_url.visit_transitions_size() == 0 ||
- typed_url.visit_transitions_size() != typed_url.visits_size()) {
- // Generate a debug assertion to help track down http://crbug.com/91473,
- // even though we gracefully handle this case by throwing away this
- // node.
- DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size());
- DVLOG(1) << "Deleting obsolete sync node with no visit "
- << "transition info.";
- obsolete_nodes.push_back(sync_child_node.GetId());
- continue;
- }
-
- if (typed_url.url().empty()) {
- DVLOG(1) << "Ignoring empty URL in sync DB";
- continue;
- }
-
- // Now, get rid of the expired visits, and if there are no un-expired
- // visits left, just ignore this node.
- sync_pb::TypedUrlSpecifics filtered_url = FilterExpiredVisits(typed_url);
- if (filtered_url.visits_size() == 0) {
- DVLOG(1) << "Ignoring expired URL in sync DB: " << filtered_url.url();
- continue;
- }
-
- if (current_urls.find(filtered_url.url()) == current_urls.end()) {
- // 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|).
- UpdateFromSyncDB(filtered_url,
- &new_visits,
- NULL,
- &updated_urls,
- &new_urls);
- local_merge_result->set_num_items_added(
- local_merge_result->num_items_added() + 1);
- }
- }
-
- // If we encountered any obsolete nodes, remove them so they don't hang
- // around and confuse people looking at the sync node browser.
- if (!obsolete_nodes.empty()) {
- for (std::vector<int64>::const_iterator it = obsolete_nodes.begin();
- it != obsolete_nodes.end();
- ++it) {
- syncer::WriteNode sync_node(&trans);
- if (sync_node.InitByIdLookup(*it) != syncer::BaseNode::INIT_OK) {
- return error_handler_->CreateAndUploadError(
- FROM_HERE,
- "Failed to fetch obsolete node.",
- model_type());
- }
- sync_node.Tombstone();
- }
- }
- syncer_merge_result->set_num_items_after_association(
- typed_url_root.GetTotalNodeCount());
- }
-
- // Since we're on the history thread, we don't have to worry about updating
- // the history database after closing the write transaction, since
- // 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.
- WriteToHistoryBackend(&new_urls, &updated_urls, &new_visits, NULL);
- local_merge_result->set_num_items_modified(updated_urls.size());
- local_merge_result->set_num_items_after_association(
- local_merge_result->num_items_before_association() +
- local_merge_result->num_items_added());
- return syncer::SyncError();
-}
-
-void TypedUrlModelAssociator::UpdateFromSyncDB(
- const sync_pb::TypedUrlSpecifics& typed_url,
- TypedUrlVisitVector* visits_to_add,
- history::VisitVector* visits_to_remove,
- history::URLRows* updated_urls,
- history::URLRows* new_urls) {
- history::URLRow new_url(GURL(typed_url.url()));
- history::VisitVector existing_visits;
- bool existing_url = history_backend_->GetURL(new_url.url(), &new_url);
- if (existing_url) {
- // This URL already exists locally - fetch the visits so we can
- // merge them below.
- if (!FixupURLAndGetVisits(&new_url, &existing_visits)) {
- // Couldn't load the visits for this URL due to some kind of DB error.
- // 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);
-
- // Figure out which visits we need to add.
- DiffVisits(existing_visits, typed_url, &visits_to_add->back().second,
- visits_to_remove);
-
- if (existing_url) {
- updated_urls->push_back(new_url);
- } else {
- new_urls->push_back(new_url);
- }
-}
-
-sync_pb::TypedUrlSpecifics TypedUrlModelAssociator::FilterExpiredVisits(
- const sync_pb::TypedUrlSpecifics& source) {
- // Make a copy of the source, then regenerate the visits.
- sync_pb::TypedUrlSpecifics specifics(source);
- specifics.clear_visits();
- specifics.clear_visit_transitions();
- for (int i = 0; i < source.visits_size(); ++i) {
- base::Time time = base::Time::FromInternalValue(source.visits(i));
- if (!history_backend_->IsExpiredVisitTime(time)) {
- specifics.add_visits(source.visits(i));
- specifics.add_visit_transitions(source.visit_transitions(i));
- }
- }
- DCHECK(specifics.visits_size() == specifics.visit_transitions_size());
- return specifics;
-}
-
-bool TypedUrlModelAssociator::DeleteAllNodes(
- syncer::WriteTransaction* trans) {
- DCHECK(expected_loop_ == base::MessageLoop::current());
-
- // Just walk through all our child nodes and delete them.
- syncer::ReadNode typed_url_root(trans);
- if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) !=
- syncer::BaseNode::INIT_OK) {
- LOG(ERROR) << "Could not lookup root node";
- return false;
- }
-
- std::vector<int64> sync_ids;
- typed_url_root.GetChildIds(&sync_ids);
-
- for (std::vector<int64>::const_iterator it = sync_ids.begin();
- it != sync_ids.end(); ++it) {
- syncer::WriteNode sync_child_node(trans);
- if (sync_child_node.InitByIdLookup(*it) != syncer::BaseNode::INIT_OK) {
- LOG(ERROR) << "Typed url node lookup failed.";
- return false;
- }
- sync_child_node.Tombstone();
- }
- return true;
-}
-
-syncer::SyncError TypedUrlModelAssociator::DisassociateModels() {
- return syncer::SyncError();
-}
-
-void TypedUrlModelAssociator::AbortAssociation() {
- base::AutoLock lock(abort_lock_);
- abort_requested_ = true;
-}
-
-bool TypedUrlModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
- DCHECK(has_nodes);
- *has_nodes = false;
- syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
- syncer::ReadNode sync_node(&trans);
- if (sync_node.InitTypeRoot(syncer::TYPED_URLS) != syncer::BaseNode::INIT_OK) {
- LOG(ERROR) << "Server did not create the top-level typed_url node. We "
- << "might be running against an out-of-date server.";
- return false;
- }
-
- // The sync model has user created nodes if the typed_url folder has any
- // children.
- *has_nodes = sync_node.HasChildren();
- return true;
-}
-
-void TypedUrlModelAssociator::WriteToHistoryBackend(
- const history::URLRows* new_urls,
- const history::URLRows* updated_urls,
- const TypedUrlVisitVector* new_visits,
- const history::VisitVector* deleted_visits) {
- if (new_urls) {
- history_backend_->AddPagesWithDetails(*new_urls, history::SOURCE_SYNCED);
- }
- if (updated_urls) {
- ++num_db_accesses_;
- // These are existing entries in the URL database. We don't verify the
- // 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.
- // In the field we sometimes run into errors on specific URLs. It's OK to
- // just continue, as we can try writing again on the next model association.
- size_t num_successful_updates = history_backend_->UpdateURLs(*updated_urls);
- num_db_errors_ += updated_urls->size() - num_successful_updates;
- }
- if (new_visits) {
- for (TypedUrlVisitVector::const_iterator visits = new_visits->begin();
- visits != new_visits->end(); ++visits) {
- // 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)) {
- ++num_db_errors_;
- DLOG(ERROR) << "Could not add visits.";
- }
- }
- }
- if (deleted_visits) {
- ++num_db_accesses_;
- if (!history_backend_->RemoveVisits(*deleted_visits)) {
- ++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.
- }
- }
-}
-
-// static
-TypedUrlModelAssociator::MergeResult TypedUrlModelAssociator::MergeUrls(
- const sync_pb::TypedUrlSpecifics& node,
- const history::URLRow& url,
- history::VisitVector* visits,
- history::URLRow* new_url,
- std::vector<history::VisitInfo>* new_visits) {
- DCHECK(new_url);
- DCHECK(!node.url().compare(url.url().spec()));
- DCHECK(!node.url().compare(new_url->url().spec()));
- DCHECK(visits->size());
- CHECK_EQ(node.visits_size(), node.visit_transitions_size());
-
- // If we have an old-format node (before we added the visits and
- // visit_transitions arrays to the protobuf) or else the node only contained
- // expired visits, so just overwrite it with our local history data.
- if (node.visits_size() == 0)
- return DIFF_UPDATE_NODE;
-
- // Convert these values only once.
- base::string16 node_title(base::UTF8ToUTF16(node.title()));
- base::Time node_last_visit = base::Time::FromInternalValue(
- node.visits(node.visits_size() - 1));
-
- // This is a bitfield representing what we'll need to update with the output
- // value.
- MergeResult different = DIFF_NONE;
-
- // Check if the non-incremented values changed.
- if ((node_title.compare(url.title()) != 0) ||
- (node.hidden() != url.hidden())) {
- // Use the values from the most recent visit.
- if (node_last_visit >= url.last_visit()) {
- new_url->set_title(node_title);
- new_url->set_hidden(node.hidden());
- different |= DIFF_LOCAL_ROW_CHANGED;
- } else {
- new_url->set_title(url.title());
- new_url->set_hidden(url.hidden());
- different |= DIFF_UPDATE_NODE;
- }
- } else {
- // No difference.
- new_url->set_title(url.title());
- new_url->set_hidden(url.hidden());
- }
-
- size_t node_num_visits = node.visits_size();
- size_t history_num_visits = visits->size();
- size_t node_visit_index = 0;
- size_t history_visit_index = 0;
- base::Time earliest_history_time = (*visits)[0].visit_time;
- // Walk through the two sets of visits and figure out if any new visits were
- // added on either side.
- while (node_visit_index < node_num_visits ||
- history_visit_index < history_num_visits) {
- // Time objects are initialized to "earliest possible time".
- base::Time node_time, history_time;
- if (node_visit_index < node_num_visits)
- node_time = base::Time::FromInternalValue(node.visits(node_visit_index));
- if (history_visit_index < history_num_visits)
- history_time = (*visits)[history_visit_index].visit_time;
- if (node_visit_index >= node_num_visits ||
- (history_visit_index < history_num_visits &&
- node_time > history_time)) {
- // We found a visit in the history DB that doesn't exist in the sync DB,
- // so mark the node as modified so the caller will update the sync node.
- different |= DIFF_UPDATE_NODE;
- ++history_visit_index;
- } else if (history_visit_index >= history_num_visits ||
- node_time < history_time) {
- // Found a visit in the sync node that doesn't exist in the history DB, so
- // add it to our list of new visits and set the appropriate flag so the
- // caller will update the history DB.
- // If the node visit is older than any existing visit in the history DB,
- // don't re-add it - this keeps us from resurrecting visits that were
- // aged out locally.
- if (node_time > earliest_history_time) {
- different |= DIFF_LOCAL_VISITS_ADDED;
- new_visits->push_back(history::VisitInfo(
- node_time,
- ui::PageTransitionFromInt(
- node.visit_transitions(node_visit_index))));
- }
- // This visit is added to visits below.
- ++node_visit_index;
- } else {
- // Same (already synced) entry found in both DBs - no need to do anything.
- ++node_visit_index;
- ++history_visit_index;
- }
- }
-
- DCHECK(CheckVisitOrdering(*visits));
- if (different & DIFF_LOCAL_VISITS_ADDED) {
- // Insert new visits into the apropriate place in the visits vector.
- history::VisitVector::iterator visit_ix = visits->begin();
- for (std::vector<history::VisitInfo>::iterator new_visit =
- new_visits->begin();
- new_visit != new_visits->end(); ++new_visit) {
- while (visit_ix != visits->end() &&
- new_visit->first > visit_ix->visit_time) {
- ++visit_ix;
- }
- visit_ix = visits->insert(visit_ix,
- history::VisitRow(url.id(), new_visit->first,
- 0, new_visit->second, 0));
- ++visit_ix;
- }
- }
- DCHECK(CheckVisitOrdering(*visits));
-
- new_url->set_last_visit(visits->back().visit_time);
- return different;
-}
-
-// static
-void TypedUrlModelAssociator::WriteToSyncNode(
- const history::URLRow& url,
- const history::VisitVector& visits,
- syncer::WriteNode* node) {
- sync_pb::TypedUrlSpecifics typed_url;
- WriteToTypedUrlSpecifics(url, visits, &typed_url);
- node->SetTypedUrlSpecifics(typed_url);
-}
-
-void TypedUrlModelAssociator::WriteToTypedUrlSpecifics(
- const history::URLRow& url,
- const history::VisitVector& visits,
- sync_pb::TypedUrlSpecifics* typed_url) {
-
- DCHECK(!url.last_visit().is_null());
- DCHECK(!visits.empty());
- DCHECK_EQ(url.last_visit().ToInternalValue(),
- visits.back().visit_time.ToInternalValue());
-
- typed_url->set_url(url.url().spec());
- typed_url->set_title(base::UTF16ToUTF8(url.title()));
- typed_url->set_hidden(url.hidden());
-
- DCHECK(CheckVisitOrdering(visits));
-
- bool only_typed = false;
- int skip_count = 0;
-
- if (visits.size() > static_cast<size_t>(kMaxTypedUrlVisits)) {
- int typed_count = 0;
- int total = 0;
- // Walk the passed-in visit vector and count the # of typed visits.
- for (history::VisitVector::const_iterator visit = visits.begin();
- visit != visits.end(); ++visit) {
- ui::PageTransition transition =
- ui::PageTransitionStripQualifier(visit->transition);
- // We ignore reload visits.
- if (transition == ui::PAGE_TRANSITION_RELOAD)
- continue;
- ++total;
- if (transition == ui::PAGE_TRANSITION_TYPED)
- ++typed_count;
- }
- // We should have at least one typed visit. This can sometimes happen if
- // the history DB has an inaccurate count for some reason (there's been
- // bugs in the history code in the past which has left users in the wild
- // with incorrect counts - http://crbug.com/84258).
- DCHECK_GT(typed_count, 0);
-
- if (typed_count > kMaxTypedUrlVisits) {
- only_typed = true;
- skip_count = typed_count - kMaxTypedUrlVisits;
- } else if (total > kMaxTypedUrlVisits) {
- skip_count = total - kMaxTypedUrlVisits;
- }
- }
-
-
- for (history::VisitVector::const_iterator visit = visits.begin();
- visit != visits.end(); ++visit) {
- ui::PageTransition transition =
- ui::PageTransitionStripQualifier(visit->transition);
- // Skip reload visits.
- if (transition == ui::PAGE_TRANSITION_RELOAD)
- continue;
-
- // If we only have room for typed visits, then only add typed visits.
- if (only_typed && transition != ui::PAGE_TRANSITION_TYPED)
- continue;
-
- if (skip_count > 0) {
- // We have too many entries to fit, so we need to skip the oldest ones.
- // Only skip typed URLs if there are too many typed URLs to fit.
- if (only_typed || transition != ui::PAGE_TRANSITION_TYPED) {
- --skip_count;
- continue;
- }
- }
- typed_url->add_visits(visit->visit_time.ToInternalValue());
- typed_url->add_visit_transitions(visit->transition);
- }
- DCHECK_EQ(skip_count, 0);
-
- if (typed_url->visits_size() == 0) {
- // If we get here, it's because we don't actually have any TYPED visits
- // even though the visit's typed_count > 0 (corrupted typed_count). So
- // let's go ahead and add a RELOAD visit at the most recent visit since
- // it's not legal to have an empty visit array (yet another workaround
- // for http://crbug.com/84258).
- typed_url->add_visits(url.last_visit().ToInternalValue());
- typed_url->add_visit_transitions(ui::PAGE_TRANSITION_RELOAD);
- }
- CHECK_GT(typed_url->visits_size(), 0);
- CHECK_LE(typed_url->visits_size(), kMaxTypedUrlVisits);
- CHECK_EQ(typed_url->visits_size(), typed_url->visit_transitions_size());
-}
-
-// static
-void TypedUrlModelAssociator::DiffVisits(
- const history::VisitVector& old_visits,
- const sync_pb::TypedUrlSpecifics& new_url,
- std::vector<history::VisitInfo>* new_visits,
- history::VisitVector* removed_visits) {
- DCHECK(new_visits);
- size_t old_visit_count = old_visits.size();
- size_t new_visit_count = new_url.visits_size();
- size_t old_index = 0;
- size_t new_index = 0;
- while (old_index < old_visit_count && new_index < new_visit_count) {
- base::Time new_visit_time =
- base::Time::FromInternalValue(new_url.visits(new_index));
- if (old_visits[old_index].visit_time < new_visit_time) {
- if (new_index > 0 && removed_visits) {
- // If there are visits missing from the start of the node, that
- // means that they were probably clipped off due to our code that
- // limits the size of the sync nodes - don't delete them from our
- // local history.
- removed_visits->push_back(old_visits[old_index]);
- }
- ++old_index;
- } else if (old_visits[old_index].visit_time > new_visit_time) {
- new_visits->push_back(history::VisitInfo(
- new_visit_time,
- ui::PageTransitionFromInt(
- new_url.visit_transitions(new_index))));
- ++new_index;
- } else {
- ++old_index;
- ++new_index;
- }
- }
-
- if (removed_visits) {
- for ( ; old_index < old_visit_count; ++old_index) {
- removed_visits->push_back(old_visits[old_index]);
- }
- }
-
- for ( ; new_index < new_visit_count; ++new_index) {
- new_visits->push_back(history::VisitInfo(
- base::Time::FromInternalValue(new_url.visits(new_index)),
- ui::PageTransitionFromInt(new_url.visit_transitions(new_index))));
- }
-}
-
-
-// static
-void TypedUrlModelAssociator::UpdateURLRowFromTypedUrlSpecifics(
- const sync_pb::TypedUrlSpecifics& typed_url, history::URLRow* new_url) {
- DCHECK_GT(typed_url.visits_size(), 0);
- CHECK_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
- new_url->set_title(base::UTF8ToUTF16(typed_url.title()));
- new_url->set_hidden(typed_url.hidden());
- // Only provide the initial value for the last_visit field - after that, let
- // the history code update the last_visit field on its own.
- if (new_url->last_visit().is_null()) {
- new_url->set_last_visit(base::Time::FromInternalValue(
- typed_url.visits(typed_url.visits_size() - 1)));
- }
-}
-
-bool TypedUrlModelAssociator::CryptoReadyIfNecessary() {
- // We only access the cryptographer while holding a transaction.
- syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
- const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
- return !encrypted_types.Has(syncer::TYPED_URLS) ||
- sync_service_->IsCryptographerReady(&trans);
-}
-
-} // namespace browser_sync
diff --git a/components/history/core/browser/typed_url_model_associator.h b/components/history/core/browser/typed_url_model_associator.h
deleted file mode 100644
index 35db2eb..0000000
--- a/components/history/core/browser/typed_url_model_associator.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_MODEL_ASSOCIATOR_H_
-#define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_MODEL_ASSOCIATOR_H_
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/sync_driver/data_type_error_handler.h"
-#include "components/sync_driver/model_associator.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
-
-class GURL;
-
-namespace base {
-class MessageLoop;
-}
-
-namespace history {
-class HistoryBackend;
-class URLRow;
-};
-
-namespace syncer {
-class WriteNode;
-class WriteTransaction;
-};
-
-namespace sync_driver {
-class SyncService;
-}
-
-namespace browser_sync {
-
-// Contains all model association related logic:
-// * Algorithm to associate typed_url model and sync model.
-// * Persisting model associations and loading them back.
-// We do not check if we have local data before this run; we always
-// merge and sync.
-class TypedUrlModelAssociator : public sync_driver::AssociatorInterface {
- public:
- typedef std::vector<std::pair<GURL, std::vector<history::VisitInfo> > >
- TypedUrlVisitVector;
-
- static syncer::ModelType model_type() { return syncer::TYPED_URLS; }
- TypedUrlModelAssociator(sync_driver::SyncService* sync_service,
- history::HistoryBackend* history_backend,
- sync_driver::DataTypeErrorHandler* error_handler);
- ~TypedUrlModelAssociator() override;
-
- // AssociatorInterface implementation.
- //
- // Iterates through the sync model looking for matched pairs of items.
- syncer::SyncError AssociateModels(
- syncer::SyncMergeResult* local_merge_result,
- syncer::SyncMergeResult* syncer_merge_result) override;
-
- // Clears all associations.
- syncer::SyncError DisassociateModels() override;
-
- // Called from the main thread, to abort the currently active model
- // association (for example, if we are shutting down).
- void AbortAssociation() override;
-
- // The has_nodes out param is true if the sync model has nodes other
- // than the permanent tagged nodes.
- bool SyncModelHasUserCreatedNodes(bool* has_nodes) override;
-
- bool CryptoReadyIfNecessary() override;
-
- // Delete all typed url nodes.
- bool DeleteAllNodes(syncer::WriteTransaction* trans);
-
- void WriteToHistoryBackend(const history::URLRows* new_urls,
- const history::URLRows* updated_urls,
- const TypedUrlVisitVector* new_visits,
- const history::VisitVector* deleted_visits);
-
- // Given a typed URL in the sync DB, looks for an existing entry in the
- // local history DB and generates a list of visits to add to the
- // history DB to bring it up to date (avoiding duplicates).
- // Updates the passed |visits_to_add| and |visits_to_remove| vectors with the
- // visits to add to/remove from the history DB, and adds a new entry to either
- // |updated_urls| or |new_urls| depending on whether the URL already existed
- // in the history DB.
- void UpdateFromSyncDB(const sync_pb::TypedUrlSpecifics& typed_url,
- TypedUrlVisitVector* visits_to_add,
- history::VisitVector* visits_to_remove,
- history::URLRows* updated_urls,
- history::URLRows* new_urls);
-
- // Given a TypedUrlSpecifics object, removes all visits that are older than
- // the current expiration time. Note that this can result in having no visits
- // at all.
- sync_pb::TypedUrlSpecifics FilterExpiredVisits(
- const sync_pb::TypedUrlSpecifics& specifics);
-
- // Returns the percentage of DB accesses that have resulted in an error.
- int GetErrorPercentage() const;
-
- // Bitfield returned from MergeUrls to specify the result of the merge.
- typedef uint32 MergeResult;
- static const MergeResult DIFF_NONE = 0;
- static const MergeResult DIFF_UPDATE_NODE = 1 << 0;
- static const MergeResult DIFF_LOCAL_ROW_CHANGED = 1 << 1;
- static const MergeResult DIFF_LOCAL_VISITS_ADDED = 1 << 2;
-
- // Merges the URL information in |typed_url| with the URL information from the
- // history database in |url| and |visits|, and returns a bitmask with the
- // results of the merge:
- // DIFF_UPDATE_NODE - changes have been made to |new_url| and |visits| which
- // should be persisted to the sync node.
- // DIFF_LOCAL_ROW_CHANGED - The history data in |new_url| should be persisted
- // to the history DB.
- // DIFF_LOCAL_VISITS_ADDED - |new_visits| contains a list of visits that
- // should be written to the history DB for this URL. Deletions are not
- // written to the DB - each client is left to age out visits on their own.
- static MergeResult MergeUrls(const sync_pb::TypedUrlSpecifics& typed_url,
- const history::URLRow& url,
- history::VisitVector* visits,
- history::URLRow* new_url,
- std::vector<history::VisitInfo>* new_visits);
- static void WriteToSyncNode(const history::URLRow& url,
- const history::VisitVector& visits,
- syncer::WriteNode* node);
-
- // Diffs the set of visits between the history DB and the sync DB, using the
- // sync DB as the canonical copy. Result is the set of |new_visits| and
- // |removed_visits| that can be applied to the history DB to make it match
- // the sync DB version. |removed_visits| can be null if the caller does not
- // care about which visits to remove.
- static void DiffVisits(const history::VisitVector& old_visits,
- const sync_pb::TypedUrlSpecifics& new_url,
- std::vector<history::VisitInfo>* new_visits,
- history::VisitVector* removed_visits);
-
- // Converts the passed URL information to a TypedUrlSpecifics structure for
- // writing to the sync DB
- static void WriteToTypedUrlSpecifics(const history::URLRow& url,
- const history::VisitVector& visits,
- sync_pb::TypedUrlSpecifics* specifics);
-
- // Fetches visits from the history DB corresponding to the passed URL. This
- // function compensates for the fact that the history DB has rather poor data
- // integrity (duplicate visits, visit timestamps that don't match the
- // last_visit timestamp, huge data sets that exhaust memory when fetched,
- // etc) by modifying the passed |url| object and |visits| vector.
- // Returns false if we could not fetch the visits for the passed URL, and
- // tracks DB error statistics internally for reporting via UMA.
- bool FixupURLAndGetVisits(history::URLRow* url,
- history::VisitVector* visits);
-
- // Updates the passed |url_row| based on the values in |specifics|. Fields
- // that are not contained in |specifics| (such as typed_count) are left
- // unchanged.
- static void UpdateURLRowFromTypedUrlSpecifics(
- const sync_pb::TypedUrlSpecifics& specifics, history::URLRow* url_row);
-
- // Helper function that determines if we should ignore a URL for the purposes
- // of sync, because it contains invalid data.
- bool ShouldIgnoreUrl(const GURL& url);
-
- protected:
- // Helper function that clears our error counters (used to reset stats after
- // model association so we can track model association errors separately).
- // Overridden by tests.
- virtual void ClearErrorStats();
-
- private:
- // Helper routine that actually does the work of associating models.
- syncer::SyncError DoAssociateModels(
- syncer::SyncMergeResult* local_merge_result,
- syncer::SyncMergeResult* syncer_merge_result);
-
- // Helper function that determines if we should ignore a URL for the purposes
- // of sync, based on the visits the URL had.
- bool ShouldIgnoreVisits(const history::VisitVector& visits);
-
- sync_driver::SyncService* sync_service_;
- history::HistoryBackend* history_backend_;
-
- base::MessageLoop* expected_loop_;
-
- bool abort_requested_;
- base::Lock abort_lock_;
-
- // Guaranteed to outlive datatypes.
- sync_driver::DataTypeErrorHandler* error_handler_;
-
- // Statistics for the purposes of tracking the percentage of DB accesses that
- // fail for each client via UMA.
- int num_db_accesses_;
- int num_db_errors_;
-
- DISALLOW_COPY_AND_ASSIGN(TypedUrlModelAssociator);
-};
-
-} // namespace browser_sync
-
-#endif // COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_MODEL_ASSOCIATOR_H_
diff --git a/components/history/core/browser/typed_url_model_associator_unittest.cc b/components/history/core/browser/typed_url_model_associator_unittest.cc
deleted file mode 100644
index ab8fec4..0000000
--- a/components/history/core/browser/typed_url_model_associator_unittest.cc
+++ /dev/null
@@ -1,432 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/thread.h"
-#include "base/time/time.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/history/core/browser/typed_url_model_associator.h"
-#include "components/sync_driver/fake_sync_service.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using browser_sync::TypedUrlModelAssociator;
-
-namespace {
-class SyncTypedUrlModelAssociatorTest : public testing::Test {
- public:
- static history::URLRow MakeTypedUrlRow(const char* url,
- const char* title,
- int typed_count,
- int64 last_visit,
- bool hidden,
- history::VisitVector* visits) {
- GURL gurl(url);
- history::URLRow history_url(gurl);
- history_url.set_title(base::UTF8ToUTF16(title));
- history_url.set_typed_count(typed_count);
- history_url.set_last_visit(
- base::Time::FromInternalValue(last_visit));
- history_url.set_hidden(hidden);
- visits->push_back(history::VisitRow(
- history_url.id(), history_url.last_visit(), 0,
- ui::PAGE_TRANSITION_RELOAD, 0));
- history_url.set_visit_count(visits->size());
- return history_url;
- }
-
- static sync_pb::TypedUrlSpecifics MakeTypedUrlSpecifics(const char* url,
- const char* title,
- int64 last_visit,
- bool hidden) {
- sync_pb::TypedUrlSpecifics typed_url;
- typed_url.set_url(url);
- typed_url.set_title(title);
- typed_url.set_hidden(hidden);
- typed_url.add_visits(last_visit);
- typed_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
- return typed_url;
- }
-
- static bool URLsEqual(history::URLRow& lhs, history::URLRow& rhs) {
- // Only compare synced fields (ignore typed_count and visit_count as those
- // are maintained by the history subsystem).
- return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
- (lhs.title().compare(rhs.title()) == 0) &&
- (lhs.hidden() == rhs.hidden());
- }
-};
-
-static void CreateModelAssociatorAsync(base::WaitableEvent* startup,
- base::WaitableEvent* aborted,
- base::WaitableEvent* done,
- TypedUrlModelAssociator** associator,
- sync_driver::SyncService* service) {
- // Grab the done lock - when we exit, this will be released and allow the
- // test to finish.
- *associator = new TypedUrlModelAssociator(service, NULL, NULL);
-
- // Signal frontend to call AbortAssociation and proceed after it's called.
- startup->Signal();
- aborted->Wait();
- syncer::SyncError error = (*associator)->AssociateModels(NULL, NULL);
- EXPECT_TRUE(error.IsSet());
- EXPECT_EQ("Association was aborted.", error.message());
- delete *associator;
- done->Signal();
-}
-
-} // namespace
-
-TEST_F(SyncTypedUrlModelAssociatorTest, MergeUrls) {
- history::VisitVector visits1;
- history::URLRow row1(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 3, false, &visits1));
- sync_pb::TypedUrlSpecifics specs1(MakeTypedUrlSpecifics("http://pie.com/",
- "pie",
- 3, false));
- history::URLRow new_row1(GURL("http://pie.com/"));
- std::vector<history::VisitInfo> new_visits1;
- EXPECT_TRUE(TypedUrlModelAssociator::MergeUrls(specs1, row1, &visits1,
- &new_row1, &new_visits1) == TypedUrlModelAssociator::DIFF_NONE);
-
- history::VisitVector visits2;
- history::URLRow row2(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 3, false, &visits2));
- sync_pb::TypedUrlSpecifics specs2(MakeTypedUrlSpecifics("http://pie.com/",
- "pie",
- 3, true));
- history::VisitVector expected_visits2;
- history::URLRow expected2(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 3, true, &expected_visits2));
- history::URLRow new_row2(GURL("http://pie.com/"));
- std::vector<history::VisitInfo> new_visits2;
- EXPECT_TRUE(TypedUrlModelAssociator::MergeUrls(specs2, row2, &visits2,
- &new_row2, &new_visits2) ==
- TypedUrlModelAssociator::DIFF_LOCAL_ROW_CHANGED);
- EXPECT_TRUE(URLsEqual(new_row2, expected2));
-
- history::VisitVector visits3;
- history::URLRow row3(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 3, false, &visits3));
- sync_pb::TypedUrlSpecifics specs3(MakeTypedUrlSpecifics("http://pie.com/",
- "pie2",
- 3, true));
- history::VisitVector expected_visits3;
- history::URLRow expected3(MakeTypedUrlRow("http://pie.com/", "pie2",
- 2, 3, true, &expected_visits3));
- history::URLRow new_row3(GURL("http://pie.com/"));
- std::vector<history::VisitInfo> new_visits3;
- EXPECT_EQ(TypedUrlModelAssociator::DIFF_LOCAL_ROW_CHANGED |
- TypedUrlModelAssociator::DIFF_NONE,
- TypedUrlModelAssociator::MergeUrls(specs3, row3, &visits3,
- &new_row3, &new_visits3));
- EXPECT_TRUE(URLsEqual(new_row3, expected3));
-
- // Create one node in history DB with timestamp of 3, and one node in sync
- // DB with timestamp of 4. Result should contain one new item (4).
- history::VisitVector visits4;
- history::URLRow row4(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 3, false, &visits4));
- sync_pb::TypedUrlSpecifics specs4(MakeTypedUrlSpecifics("http://pie.com/",
- "pie2",
- 4, false));
- history::VisitVector expected_visits4;
- history::URLRow expected4(MakeTypedUrlRow("http://pie.com/", "pie2",
- 2, 4, false, &expected_visits4));
- history::URLRow new_row4(GURL("http://pie.com/"));
- std::vector<history::VisitInfo> new_visits4;
- EXPECT_EQ(TypedUrlModelAssociator::DIFF_UPDATE_NODE |
- TypedUrlModelAssociator::DIFF_LOCAL_ROW_CHANGED |
- TypedUrlModelAssociator::DIFF_LOCAL_VISITS_ADDED,
- TypedUrlModelAssociator::MergeUrls(specs4, row4, &visits4,
- &new_row4, &new_visits4));
- EXPECT_EQ(1U, new_visits4.size());
- EXPECT_EQ(specs4.visits(0), new_visits4[0].first.ToInternalValue());
- EXPECT_TRUE(URLsEqual(new_row4, expected4));
- EXPECT_EQ(2U, visits4.size());
-
- history::VisitVector visits5;
- history::URLRow row5(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 4, false, &visits5));
- sync_pb::TypedUrlSpecifics specs5(MakeTypedUrlSpecifics("http://pie.com/",
- "pie",
- 3, false));
- history::VisitVector expected_visits5;
- history::URLRow expected5(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 3, false, &expected_visits5));
- history::URLRow new_row5(GURL("http://pie.com/"));
- std::vector<history::VisitInfo> new_visits5;
-
- // UPDATE_NODE should be set because row5 has a newer last_visit timestamp.
- EXPECT_EQ(TypedUrlModelAssociator::DIFF_UPDATE_NODE |
- TypedUrlModelAssociator::DIFF_NONE,
- TypedUrlModelAssociator::MergeUrls(specs5, row5, &visits5,
- &new_row5, &new_visits5));
- EXPECT_TRUE(URLsEqual(new_row5, expected5));
- EXPECT_EQ(0U, new_visits5.size());
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, MergeUrlsAfterExpiration) {
- // Tests to ensure that we don't resurrect expired URLs (URLs that have been
- // deleted from the history DB but still exist in the sync DB).
-
- // First, create a history row that has two visits, with timestamps 2 and 3.
- history::VisitVector(history_visits);
- history_visits.push_back(history::VisitRow(
- 0, base::Time::FromInternalValue(2), 0, ui::PAGE_TRANSITION_TYPED,
- 0));
- history::URLRow history_url(MakeTypedUrlRow("http://pie.com/", "pie",
- 2, 3, false, &history_visits));
-
- // Now, create a sync node with visits at timestamps 1, 2, 3, 4.
- sync_pb::TypedUrlSpecifics node(MakeTypedUrlSpecifics("http://pie.com/",
- "pie", 1, false));
- node.add_visits(2);
- node.add_visits(3);
- node.add_visits(4);
- node.add_visit_transitions(2);
- node.add_visit_transitions(3);
- node.add_visit_transitions(4);
- history::URLRow new_history_url(history_url.url());
- std::vector<history::VisitInfo> new_visits;
- EXPECT_EQ(TypedUrlModelAssociator::DIFF_NONE |
- TypedUrlModelAssociator::DIFF_LOCAL_VISITS_ADDED,
- TypedUrlModelAssociator::MergeUrls(
- node, history_url, &history_visits, &new_history_url,
- &new_visits));
- EXPECT_TRUE(URLsEqual(history_url, new_history_url));
- EXPECT_EQ(1U, new_visits.size());
- EXPECT_EQ(4U, new_visits[0].first.ToInternalValue());
- // We should not sync the visit with timestamp #1 since it is earlier than
- // any other visit for this URL in the history DB. But we should sync visit
- // #4.
- EXPECT_EQ(3U, history_visits.size());
- EXPECT_EQ(2U, history_visits[0].visit_time.ToInternalValue());
- EXPECT_EQ(3U, history_visits[1].visit_time.ToInternalValue());
- EXPECT_EQ(4U, history_visits[2].visit_time.ToInternalValue());
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, DiffVisitsSame) {
- history::VisitVector old_visits;
- sync_pb::TypedUrlSpecifics new_url;
-
- const int64 visits[] = { 1024, 2065, 65534, 1237684 };
-
- for (size_t c = 0; c < arraysize(visits); ++c) {
- old_visits.push_back(history::VisitRow(
- 0, base::Time::FromInternalValue(visits[c]), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
- new_url.add_visits(visits[c]);
- new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
- }
-
- std::vector<history::VisitInfo> new_visits;
- history::VisitVector removed_visits;
-
- TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
- &new_visits, &removed_visits);
- EXPECT_TRUE(new_visits.empty());
- EXPECT_TRUE(removed_visits.empty());
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, DiffVisitsRemove) {
- history::VisitVector old_visits;
- sync_pb::TypedUrlSpecifics new_url;
-
- const int64 visits_left[] = { 1, 2, 1024, 1500, 2065, 6000,
- 65534, 1237684, 2237684 };
- const int64 visits_right[] = { 1024, 2065, 65534, 1237684 };
-
- // DiffVisits will not remove the first visit, because we never delete visits
- // from the start of the array (since those visits can get truncated by the
- // size-limiting code).
- const int64 visits_removed[] = { 1500, 6000, 2237684 };
-
- for (size_t c = 0; c < arraysize(visits_left); ++c) {
- old_visits.push_back(history::VisitRow(
- 0, base::Time::FromInternalValue(visits_left[c]), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
- }
-
- for (size_t c = 0; c < arraysize(visits_right); ++c) {
- new_url.add_visits(visits_right[c]);
- new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
- }
-
- std::vector<history::VisitInfo> new_visits;
- history::VisitVector removed_visits;
-
- TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
- &new_visits, &removed_visits);
- EXPECT_TRUE(new_visits.empty());
- ASSERT_EQ(removed_visits.size(), arraysize(visits_removed));
- for (size_t c = 0; c < arraysize(visits_removed); ++c) {
- EXPECT_EQ(removed_visits[c].visit_time.ToInternalValue(),
- visits_removed[c]);
- }
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, DiffVisitsAdd) {
- history::VisitVector old_visits;
- sync_pb::TypedUrlSpecifics new_url;
-
- const int64 visits_left[] = { 1024, 2065, 65534, 1237684 };
- const int64 visits_right[] = { 1, 1024, 1500, 2065, 6000,
- 65534, 1237684, 2237684 };
-
- const int64 visits_added[] = { 1, 1500, 6000, 2237684 };
-
- for (size_t c = 0; c < arraysize(visits_left); ++c) {
- old_visits.push_back(history::VisitRow(
- 0, base::Time::FromInternalValue(visits_left[c]), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
- }
-
- for (size_t c = 0; c < arraysize(visits_right); ++c) {
- new_url.add_visits(visits_right[c]);
- new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
- }
-
- std::vector<history::VisitInfo> new_visits;
- history::VisitVector removed_visits;
-
- TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
- &new_visits, &removed_visits);
- EXPECT_TRUE(removed_visits.empty());
- ASSERT_TRUE(new_visits.size() == arraysize(visits_added));
- for (size_t c = 0; c < arraysize(visits_added); ++c) {
- EXPECT_EQ(new_visits[c].first.ToInternalValue(),
- visits_added[c]);
- EXPECT_EQ(new_visits[c].second, ui::PAGE_TRANSITION_TYPED);
- }
-}
-
-static history::VisitRow CreateVisit(ui::PageTransition type,
- int64 timestamp) {
- return history::VisitRow(0, base::Time::FromInternalValue(timestamp), 0,
- type, 0);
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, WriteTypedUrlSpecifics) {
- history::VisitVector visits;
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, 1));
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, 2));
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, 3));
-
- history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 100, false, &visits));
- sync_pb::TypedUrlSpecifics typed_url;
- TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
- // RELOAD visits should be removed.
- EXPECT_EQ(2, typed_url.visits_size());
- EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
- EXPECT_EQ(1, typed_url.visits(0));
- EXPECT_EQ(3, typed_url.visits(1));
- EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
- ui::PageTransitionFromInt(typed_url.visit_transitions(0)));
- EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
- ui::PageTransitionFromInt(typed_url.visit_transitions(1)));
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, TooManyVisits) {
- history::VisitVector visits;
- int64 timestamp = 1000;
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
- for (int i = 0 ; i < 100; ++i) {
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++));
- }
- history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, timestamp++, false, &visits));
- sync_pb::TypedUrlSpecifics typed_url;
- TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
- // # visits should be capped at 100.
- EXPECT_EQ(100, typed_url.visits_size());
- EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
- EXPECT_EQ(1000, typed_url.visits(0));
- // Visit with timestamp of 1001 should be omitted since we should have
- // skipped that visit to stay under the cap.
- EXPECT_EQ(1002, typed_url.visits(1));
- EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
- ui::PageTransitionFromInt(typed_url.visit_transitions(0)));
- EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
- ui::PageTransitionFromInt(typed_url.visit_transitions(1)));
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, TooManyTypedVisits) {
- history::VisitVector visits;
- int64 timestamp = 1000;
- for (int i = 0 ; i < 102; ++i) {
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++));
- visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, timestamp++));
- }
- history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, timestamp++, false, &visits));
- sync_pb::TypedUrlSpecifics typed_url;
- TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
- // # visits should be capped at 100.
- EXPECT_EQ(100, typed_url.visits_size());
- EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
- // First two typed visits should be skipped.
- EXPECT_EQ(1006, typed_url.visits(0));
-
- // Ensure there are no non-typed visits since that's all that should fit.
- for (int i = 0; i < typed_url.visits_size(); ++i) {
- EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
- ui::PageTransitionFromInt(typed_url.visit_transitions(i)));
- }
-}
-
-TEST_F(SyncTypedUrlModelAssociatorTest, NoTypedVisits) {
- history::VisitVector visits;
- history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
- 1, 1000, false, &visits));
- sync_pb::TypedUrlSpecifics typed_url;
- TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
- // URLs with no typed URL visits should be translated to a URL with one
- // reload visit.
- EXPECT_EQ(1, typed_url.visits_size());
- EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
- // First two typed visits should be skipped.
- EXPECT_EQ(1000, typed_url.visits(0));
- EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD,
- ui::PageTransitionFromInt(typed_url.visit_transitions(0)));
-}
-
-// This test verifies that we can abort model association from the UI thread.
-// We start up the model associator on the DB thread, block until we abort the
-// association on the UI thread, then ensure that AssociateModels() returns
-// false.
-TEST_F(SyncTypedUrlModelAssociatorTest, TestAbort) {
- base::Thread db_thread("DB_Thread");
- db_thread.Start();
-
- base::WaitableEvent startup(false, false);
- base::WaitableEvent aborted(false, false);
- base::WaitableEvent done(false, false);
- sync_driver::FakeSyncService service;
- TypedUrlModelAssociator* associator(NULL);
- // Fire off to the DB thread to create the model associator and start
- // model association.
- base::Closure callback = base::Bind(
- &CreateModelAssociatorAsync, &startup, &aborted, &done, &associator,
- &service);
- db_thread.task_runner()->PostTask(FROM_HERE, callback);
- // Wait for the model associator to get created and start assocation.
- ASSERT_TRUE(startup.TimedWait(TestTimeouts::action_timeout()));
- // Abort the model assocation - this should be callable from any thread.
- associator->AbortAssociation();
- // Tell the remote thread to continue.
- aborted.Signal();
- // Block until CreateModelAssociator() exits.
- ASSERT_TRUE(done.TimedWait(TestTimeouts::action_timeout()));
- db_thread.Stop();
-}
diff --git a/components/history/core/browser/typed_url_syncable_service.cc b/components/history/core/browser/typed_url_syncable_service.cc
index 7fb5410..1aaaeec 100644
--- a/components/history/core/browser/typed_url_syncable_service.cc
+++ b/components/history/core/browser/typed_url_syncable_service.cc
@@ -61,7 +61,11 @@ static bool CheckVisitOrdering(const VisitVector& visits) {
TypedUrlSyncableService::TypedUrlSyncableService(
HistoryBackend* history_backend)
- : history_backend_(history_backend), processing_syncer_changes_(false) {
+ : history_backend_(history_backend),
+ processing_syncer_changes_(false),
+ num_db_accesses_(0),
+ num_db_errors_(0),
+ history_backend_observer_(this) {
DCHECK(history_backend_);
DCHECK(thread_checker_.CalledOnValidThread());
}
@@ -88,16 +92,6 @@ syncer::SyncMergeResult TypedUrlSyncableService::MergeDataAndStartSyncing(
DVLOG(1) << "Associating TypedUrl: MergeDataAndStartSyncing";
- // Get all the typed urls from the history db.
- history::URLRows typed_urls;
- ++num_db_accesses_;
- if (!history_backend_->GetAllTypedURLs(&typed_urls)) {
- ++num_db_errors_;
- sync_error_handler_->CreateAndUploadError(
- FROM_HERE, "Could not get the typed_url entries.");
- return merge_result;
- }
-
// Create a mapping of all local data by URLID. These will be narrowed down
// by CreateOrUpdateUrl() to include only the entries different from sync
// server data.
@@ -105,20 +99,33 @@ syncer::SyncMergeResult TypedUrlSyncableService::MergeDataAndStartSyncing(
// Get all the visits and map the URLRows by URL.
UrlVisitVectorMap visit_vectors;
- for (history::URLRows::iterator iter = typed_urls.begin();
- iter != typed_urls.end();) {
- DCHECK_EQ(0U, visit_vectors.count(iter->url()));
- if (!FixupURLAndGetVisits(&(*iter), &(visit_vectors[iter->url()])) ||
- ShouldIgnoreUrl(iter->url()) ||
- ShouldIgnoreVisits(visit_vectors[iter->url()])) {
- // Ignore this URL if we couldn't load the visits or if there's some
- // other problem with it (it was empty, or imported and never visited).
- iter = typed_urls.erase(iter);
- } else {
- // Add url to map.
- new_db_urls[iter->url()] =
- std::make_pair(syncer::SyncChange::ACTION_ADD, iter);
- ++iter;
+
+ {
+ // Get all the typed urls from the history db.
+ history::URLRows typed_urls;
+ ++num_db_accesses_;
+ if (!history_backend_->GetAllTypedURLs(&typed_urls)) {
+ ++num_db_errors_;
+ merge_result.set_error(sync_error_handler_->CreateAndUploadError(
+ FROM_HERE, "Could not get the typed_url entries."));
+ return merge_result;
+ }
+
+ for (history::URLRows::iterator iter = typed_urls.begin();
+ iter != typed_urls.end();) {
+ DCHECK_EQ(0U, visit_vectors.count(iter->url()));
+ if (!FixupURLAndGetVisits(&(*iter), &(visit_vectors[iter->url()])) ||
+ ShouldIgnoreUrl(iter->url()) ||
+ ShouldIgnoreVisits(visit_vectors[iter->url()])) {
+ // Ignore this URL if we couldn't load the visits or if there's some
+ // other problem with it (it was empty, or imported and never visited).
+ iter = typed_urls.erase(iter);
+ } else {
+ // Add url to map.
+ new_db_urls[iter->url()] =
+ std::make_pair(syncer::SyncChange::ACTION_ADD, *iter);
+ ++iter;
+ }
}
}
@@ -164,15 +171,14 @@ syncer::SyncMergeResult TypedUrlSyncableService::MergeDataAndStartSyncing(
continue;
}
- CreateOrUpdateUrl(typed_url, &typed_urls, &new_db_urls, &visit_vectors,
- &new_synced_urls, &new_synced_visits,
- &updated_synced_urls);
+ CreateOrUpdateUrl(typed_url, &new_db_urls, &visit_vectors, &new_synced_urls,
+ &new_synced_visits, &updated_synced_urls);
}
for (TypedUrlMap::iterator i = new_db_urls.begin(); i != new_db_urls.end();
++i) {
std::string tag = i->first.spec();
- AddTypedUrlToChangeList(i->second.first, *(i->second.second),
+ AddTypedUrlToChangeList(i->second.first, i->second.second,
visit_vectors[i->first], tag, &new_changes);
// Add url to cache of sync state, if not already cached
@@ -188,6 +194,8 @@ syncer::SyncMergeResult TypedUrlSyncableService::MergeDataAndStartSyncing(
&new_synced_visits, NULL);
}
+ history_backend_observer_.Add(history_backend_);
+
UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlMergeAndStartSyncingErrors",
GetErrorPercentage());
ClearErrorStats();
@@ -202,6 +210,8 @@ void TypedUrlSyncableService::StopSyncing(syncer::ModelType type) {
// Clear cache of server state.
synced_typed_urls_.clear();
+ history_backend_observer_.RemoveAll();
+
ClearErrorStats();
sync_processor_.reset();
@@ -370,7 +380,6 @@ void TypedUrlSyncableService::OnURLsDeleted(
void TypedUrlSyncableService::CreateOrUpdateUrl(
const sync_pb::TypedUrlSpecifics& typed_url,
- history::URLRows* typed_urls,
TypedUrlMap* loaded_data,
UrlVisitVectorMap* visit_vectors,
history::URLRows* new_synced_urls,
@@ -405,10 +414,6 @@ void TypedUrlSyncableService::CreateOrUpdateUrl(
bool is_existing_url =
history_backend_->GetURL(untyped_url.url(), &untyped_url);
if (is_existing_url) {
- // This URL already exists locally, but was not grabbed earlier
- // because |typed_count| is 0
- DCHECK_EQ(untyped_url.typed_count(), 0);
-
// Add a new entry to |loaded_data|, and set the iterator to it.
history::VisitVector untyped_visits;
if (!FixupURLAndGetVisits(&untyped_url, &untyped_visits)) {
@@ -421,12 +426,9 @@ void TypedUrlSyncableService::CreateOrUpdateUrl(
(*visit_vectors)[untyped_url.url()] = untyped_visits;
// Store row info that will be used to update sync's visits.
- history::URLRows::iterator ri =
- typed_urls->insert(typed_urls->end(), untyped_url);
(*loaded_data)[untyped_url.url()] =
- std::pair<syncer::SyncChange::SyncChangeType,
- history::URLRows::iterator>(
- syncer::SyncChange::ACTION_UPDATE, ri);
+ std::pair<syncer::SyncChange::SyncChangeType, history::URLRow>(
+ syncer::SyncChange::ACTION_UPDATE, untyped_url);
// Set iterator |it| to point to this entry.
it = loaded_data->find(untyped_url.url());
@@ -463,21 +465,21 @@ void TypedUrlSyncableService::CreateOrUpdateUrl(
std::vector<history::VisitInfo> added_visits;
// Empty URLs should be filtered out by ShouldIgnoreUrl() previously.
- DCHECK(!it->second.second->url().spec().empty());
+ DCHECK(!it->second.second.url().spec().empty());
// Initialize fields in |new_url| to the same values as the fields in
// the existing URLRow in the history DB. This is needed because we
// overwrite the existing value in WriteToHistoryBackend(), but some of
// the values in that structure are not synced (like typed_count).
- history::URLRow new_url(*(it->second.second));
+ history::URLRow new_url(it->second.second);
- MergeResult difference = MergeUrls(sync_url, *(it->second.second), &visits,
- &new_url, &added_visits);
+ MergeResult difference =
+ MergeUrls(sync_url, it->second.second, &visits, &new_url, &added_visits);
if (difference != DIFF_NONE) {
+ it->second.second = new_url;
if (difference & DIFF_UPDATE_NODE) {
// Edit map entry to reflect update to sync.
- *(it->second.second) = new_url;
it->second.first = syncer::SyncChange::ACTION_UPDATE;
// We don't want to resurrect old visits that have been aged out by
// other clients, so remove all visits that are older than the
@@ -504,7 +506,7 @@ void TypedUrlSyncableService::CreateOrUpdateUrl(
}
if (difference & DIFF_LOCAL_ROW_CHANGED) {
// Add entry to updated_synced_urls to update the local db.
- DCHECK_EQ(it->second.second->id(), new_url.id());
+ DCHECK_EQ(it->second.second.id(), new_url.id());
updated_synced_urls->push_back(new_url);
}
if (difference & DIFF_LOCAL_VISITS_ADDED) {
@@ -525,23 +527,14 @@ sync_pb::TypedUrlSpecifics TypedUrlSyncableService::FilterExpiredVisits(
sync_pb::TypedUrlSpecifics specifics(source);
specifics.clear_visits();
specifics.clear_visit_transitions();
- int typed_count = 0;
for (int i = 0; i < source.visits_size(); ++i) {
base::Time time = base::Time::FromInternalValue(source.visits(i));
if (!history_backend_->IsExpiredVisitTime(time)) {
specifics.add_visits(source.visits(i));
specifics.add_visit_transitions(source.visit_transitions(i));
- if (source.visit_transitions(i) == ui::PAGE_TRANSITION_TYPED)
- ++typed_count;
}
}
DCHECK(specifics.visits_size() == specifics.visit_transitions_size());
- // Treat specifics with no non-expired typed visits as though they have no
- // non-expired visits of any kind
- if (typed_count == 0) {
- specifics.clear_visits();
- specifics.clear_visit_transitions();
- }
return specifics;
}
diff --git a/components/history/core/browser/typed_url_syncable_service.h b/components/history/core/browser/typed_url_syncable_service.h
index ed7d492..da396dc 100644
--- a/components/history/core/browser/typed_url_syncable_service.h
+++ b/components/history/core/browser/typed_url_syncable_service.h
@@ -8,6 +8,7 @@
#include <set>
#include <vector>
+#include "base/scoped_observer.h"
#include "base/threading/thread_checker.h"
#include "components/history/core/browser/history_backend_observer.h"
#include "components/history/core/browser/history_types.h"
@@ -68,6 +69,15 @@ class TypedUrlSyncableService : public syncer::SyncableService,
const history::URLRows& deleted_rows,
const std::set<GURL>& favicon_urls) override;
+ // Returns the percentage of DB accesses that have resulted in an error.
+ int GetErrorPercentage() const;
+
+ // Converts the passed URL information to a TypedUrlSpecifics structure for
+ // writing to the sync DB.
+ static void WriteToTypedUrlSpecifics(const URLRow& url,
+ const VisitVector& visits,
+ sync_pb::TypedUrlSpecifics* specifics);
+
private:
friend class TypedUrlSyncableServiceTest;
@@ -77,9 +87,8 @@ class TypedUrlSyncableService : public syncer::SyncableService,
// This is a helper map used only in Merge/Process* functions. The lifetime
// of the iterator is longer than the map object.
- typedef std::map<GURL,
- std::pair<syncer::SyncChange::SyncChangeType,
- URLRows::iterator>> TypedUrlMap;
+ typedef std::map<GURL, std::pair<syncer::SyncChange::SyncChangeType, URLRow>>
+ TypedUrlMap;
// This is a helper map used to associate visit vectors from the history db
// to the typed urls in the above map.
@@ -93,17 +102,17 @@ class TypedUrlSyncableService : public syncer::SyncableService,
static const MergeResult DIFF_LOCAL_VISITS_ADDED = 1 << 2;
// Helper method for getting the set of synced urls.
+ // Set it as virtual for testing.
void GetSyncedUrls(std::set<GURL>* urls) const;
// Helper function that clears our error counters (used to reset stats after
// model association so we can track model association errors separately).
- void ClearErrorStats();
+ virtual void ClearErrorStats();
// Compares |typed_url| from the server against local history to decide how
// to merge any existing data, and updates appropriate data containers to
// write to server and backend.
void CreateOrUpdateUrl(const sync_pb::TypedUrlSpecifics& typed_url,
- history::URLRows* typed_urls,
TypedUrlMap* loaded_data,
UrlVisitVectorMap* visit_vectors,
history::URLRows* new_synced_urls,
@@ -138,9 +147,6 @@ class TypedUrlSyncableService : public syncer::SyncableService,
const TypedUrlVisitVector* new_visits,
const history::VisitVector* deleted_visits);
- // Returns the percentage of DB accesses that have resulted in an error.
- int GetErrorPercentage() const;
-
// Helper function that determines if we should ignore a URL for the purposes
// of sync, because it contains invalid data.
bool ShouldIgnoreUrl(const GURL& url);
@@ -168,12 +174,6 @@ class TypedUrlSyncableService : public syncer::SyncableService,
std::string title,
syncer::SyncChangeList* change_list);
- // Converts the passed URL information to a TypedUrlSpecifics structure for
- // writing to the sync DB.
- static void WriteToTypedUrlSpecifics(const URLRow& url,
- const VisitVector& visits,
- sync_pb::TypedUrlSpecifics* specifics);
-
// Fills |new_url| with formatted data from |typed_url|.
static void UpdateURLRowFromTypedUrlSpecifics(
const sync_pb::TypedUrlSpecifics& typed_url,
@@ -234,6 +234,9 @@ class TypedUrlSyncableService : public syncer::SyncableService,
base::ThreadChecker thread_checker_;
+ ScopedObserver<history::HistoryBackend, history::HistoryBackendObserver>
+ history_backend_observer_;
+
DISALLOW_COPY_AND_ASSIGN(TypedUrlSyncableService);
};
diff --git a/components/history/core/browser/typed_url_syncable_service_unittest.cc b/components/history/core/browser/typed_url_syncable_service_unittest.cc
index fdd7fce..a3405da 100644
--- a/components/history/core/browser/typed_url_syncable_service_unittest.cc
+++ b/components/history/core/browser/typed_url_syncable_service_unittest.cc
@@ -210,7 +210,7 @@ class TestHistoryBackend : public HistoryBackend {
class TypedUrlSyncableServiceTest : public testing::Test {
public:
- TypedUrlSyncableServiceTest() {}
+ TypedUrlSyncableServiceTest() : typed_url_sync_service_(NULL) {}
~TypedUrlSyncableServiceTest() override {}
void SetUp() override {
@@ -219,8 +219,8 @@ class TypedUrlSyncableServiceTest : public testing::Test {
fake_history_backend_->Init(
std::string(), false,
TestHistoryDatabaseParamsForPath(test_dir_.path()));
- typed_url_sync_service_.reset(
- new TypedUrlSyncableService(fake_history_backend_.get()));
+ typed_url_sync_service_ =
+ fake_history_backend_->GetTypedUrlSyncableService();
fake_change_processor_.reset(new syncer::FakeSyncChangeProcessor);
}
@@ -288,7 +288,7 @@ class TypedUrlSyncableServiceTest : public testing::Test {
base::MessageLoop message_loop_;
base::ScopedTempDir test_dir_;
scoped_refptr<TestHistoryBackend> fake_history_backend_;
- scoped_ptr<TypedUrlSyncableService> typed_url_sync_service_;
+ TypedUrlSyncableService* typed_url_sync_service_;
scoped_ptr<syncer::FakeSyncChangeProcessor> fake_change_processor_;
};
@@ -305,6 +305,7 @@ void TypedUrlSyncableServiceTest::StartSyncing(
fake_change_processor_.get())),
scoped_ptr<syncer::SyncErrorFactory>(
new syncer::SyncErrorFactoryMock()));
+ typed_url_sync_service_->history_backend_observer_.RemoveAll();
EXPECT_FALSE(result.error().IsSet()) << result.error().message();
}
@@ -316,7 +317,7 @@ bool TypedUrlSyncableServiceTest::BuildAndPushLocalChanges(
std::vector<VisitVector>* visit_vectors) {
unsigned int total_urls = num_typed_urls + num_reload_urls;
DCHECK(urls.size() >= total_urls);
- if (!typed_url_sync_service_.get())
+ if (!typed_url_sync_service_)
return false;
if (total_urls) {