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

Unified Diff: chrome/browser/search_engines/template_url_service.cc

Issue 10826309: Rewrite TemplateURLService's SyncableService implmentation to avoid sending ACTION_DELETEs to Sync. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: pkasting nit Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/search_engines/template_url_service.cc
diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc
index d3dce0ec3bb8f40ff231b46e6a11cc8c27b4b9dc..22d77b70df24c73382a2333ce694b79fc98c00b1 100644
--- a/chrome/browser/search_engines/template_url_service.cc
+++ b/chrome/browser/search_engines/template_url_service.cc
@@ -194,8 +194,15 @@ std::string OldBaseURLSearchTermsData::GoogleBaseURLValue() const {
return old_base_url;
}
-} // namespace
+// Returns true if |turl|'s GUID is not found inside |sync_data|. This is to be
+// used in MergeDataAndStartSyncing to differentiate between TemplateURLs from
+// Sync and TemplateURLs that were initially local, assuming |sync_data| is the
+// |initial_sync_data| parameter.
+bool IsFromSync(const TemplateURL* turl, const SyncDataMap& sync_data) {
+ return !!sync_data.count(turl->sync_guid());
+}
+} // namespace
class TemplateURLService::LessWithPrefix {
public:
@@ -1012,17 +1019,19 @@ syncer::SyncError TemplateURLService::ProcessSyncChanges(
LOG(ERROR) << "Trying to add an existing TemplateURL.";
continue;
}
- std::string guid = turl->sync_guid();
- if (!existing_keyword_turl || ResolveSyncKeywordConflict(turl.get(),
- existing_keyword_turl, &new_changes)) {
- // Force the local ID to kInvalidTemplateURLID so we can add it.
- TemplateURLData data(turl->data());
- data.id = kInvalidTemplateURLID;
- Add(new TemplateURL(profile_, data));
-
- // Possibly set the newly added |turl| as the default search provider.
- SetDefaultSearchProviderIfNewlySynced(guid);
+ const std::string guid = turl->sync_guid();
+ if (existing_keyword_turl) {
+ // Resolve any conflicts so we can safely add the new entry.
+ ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
+ &new_changes);
}
+ // Force the local ID to kInvalidTemplateURLID so we can add it.
+ TemplateURLData data(turl->data());
+ data.id = kInvalidTemplateURLID;
+ Add(new TemplateURL(profile_, data));
+
+ // Possibly set the newly added |turl| as the default search provider.
+ SetDefaultSearchProviderIfNewlySynced(guid);
} else if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE) {
if (!existing_turl) {
NOTREACHED() << "Unexpected sync change state.";
@@ -1032,16 +1041,11 @@ syncer::SyncError TemplateURLService::ProcessSyncChanges(
LOG(ERROR) << "Trying to update a non-existent TemplateURL.";
continue;
}
- // Possibly resolve a keyword conflict if they have the same keywords but
- // are not the same entry.
- if (existing_keyword_turl && (existing_keyword_turl != existing_turl) &&
- !ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
- &new_changes)) {
- // Note that because we're processing changes, this Remove() call won't
- // generate an ACTION_DELETE; but ResolveSyncKeywordConflict() did
- // already, so we should be OK.
- Remove(existing_turl);
- continue;
+ if (existing_keyword_turl && (existing_keyword_turl != existing_turl)) {
+ // Resolve any conflicts with other entries so we can safely update the
+ // keyword.
+ ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
+ &new_changes);
}
UIThreadSearchTermsData search_terms_data(existing_turl->profile());
if (UpdateNoNotify(existing_turl, *turl, search_terms_data))
@@ -1129,6 +1133,7 @@ syncer::SyncError TemplateURLService::MergeDataAndStartSyncing(
}
if (local_turl) {
+ DCHECK(IsFromSync(local_turl, sync_data_map));
// This local search engine is already synced. If the timestamp differs
// from Sync, we need to update locally or to the cloud. Note that if the
// timestamps are equal, we touch neither.
@@ -1151,36 +1156,12 @@ syncer::SyncError TemplateURLService::MergeDataAndStartSyncing(
}
local_data_map.erase(iter->first);
} else {
- // The search engine from the cloud has not been synced locally, but there
- // might be a local search engine that is a duplicate that needs to be
- // merged.
- TemplateURL* dupe_turl = FindDuplicateOfSyncTemplateURL(*sync_turl);
- if (dupe_turl) {
- // Merge duplicates and remove the processed local TURL from the map.
- std::string old_guid = dupe_turl->sync_guid();
- MergeSyncAndLocalURLDuplicates(sync_turl.release(), dupe_turl,
- &new_changes);
- local_data_map.erase(old_guid);
- } else {
- std::string guid = sync_turl->sync_guid();
- // Keyword conflict is possible in this case. Resolve it first before
- // adding the new TemplateURL. Note that we don't remove the local TURL
- // from local_data_map in this case as it may still need to be pushed to
- // the cloud. We also explicitly don't resolve conflicts against
- // extension keywords; see comments in ProcessSyncChanges().
- TemplateURL* existing_keyword_turl =
- FindNonExtensionTemplateURLForKeyword(sync_turl->keyword());
- if (!existing_keyword_turl || ResolveSyncKeywordConflict(
- sync_turl.get(), existing_keyword_turl, &new_changes)) {
- // Force the local ID to kInvalidTemplateURLID so we can add it.
- TemplateURLData data(sync_turl->data());
- data.id = kInvalidTemplateURLID;
- Add(new TemplateURL(profile_, data));
-
- // Possibly set the newly added |turl| as the default search provider.
- SetDefaultSearchProviderIfNewlySynced(guid);
- }
- }
+ // The search engine from the cloud has not been synced locally. Merge it
+ // into our local model. This will handle any conflicts with local (and
+ // already-synced) TemplateURLs. It will prefer to keep entries from Sync
+ // over not-yet-synced TemplateURLs.
+ MergeInSyncTemplateURL(sync_turl.get(), sync_data_map, &new_changes,
+ &local_data_map);
}
}
@@ -2324,125 +2305,129 @@ string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl,
return keyword_candidate;
}
-bool TemplateURLService::ResolveSyncKeywordConflict(
- TemplateURL* sync_turl,
- TemplateURL* local_turl,
+bool TemplateURLService::IsLocalTemplateURLBetter(
+ const TemplateURL* local_turl,
+ const TemplateURL* sync_turl) {
+ DCHECK(GetTemplateURLForGUID(local_turl->sync_guid()));
+ return local_turl->last_modified() > sync_turl->last_modified() ||
+ local_turl->created_by_policy() ||
+ local_turl== GetDefaultSearchProvider();
+}
+
+void TemplateURLService::ResolveSyncKeywordConflict(
+ TemplateURL* unapplied_sync_turl,
+ TemplateURL* applied_sync_turl,
syncer::SyncChangeList* change_list) {
DCHECK(loaded_);
- DCHECK(sync_turl);
- DCHECK(local_turl);
- DCHECK(sync_turl->sync_guid() != local_turl->sync_guid());
- DCHECK(!local_turl->IsExtensionKeyword());
+ DCHECK(unapplied_sync_turl);
+ DCHECK(applied_sync_turl);
DCHECK(change_list);
-
- const bool local_is_better =
- (local_turl->last_modified() > sync_turl->last_modified()) ||
- local_turl->created_by_policy() ||
- (local_turl == GetDefaultSearchProvider());
- const bool can_replace_local = CanReplace(local_turl);
- if (CanReplace(sync_turl) && (local_is_better || !can_replace_local)) {
- syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*sync_turl);
- change_list->push_back(syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_DELETE,
- sync_data));
- return false;
- }
- if (can_replace_local) {
- // Since we're processing sync changes, the upcoming Remove() won't generate
- // an ACTION_DELETE. We need to do it manually to keep the server in sync
- // with us. Note that if we're being called from
- // MergeDataAndStartSyncing(), and this TemplateURL was pre-existing rather
- // than having just been brought down, then this is wrong, because the
- // server doesn't yet know about this entity; but in this case,
- // PruneSyncChanges() will prune out the ACTION_DELETE we create here.
- syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
- change_list->push_back(syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_DELETE,
- sync_data));
- Remove(local_turl);
- } else if (local_is_better) {
- string16 new_keyword = UniquifyKeyword(*sync_turl, false);
- DCHECK(!GetTemplateURLForKeyword(new_keyword));
- sync_turl->data_.SetKeyword(new_keyword);
- // If we update the cloud TURL, we need to push an update back to sync
- // informing it that something has changed.
- syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*sync_turl);
- change_list->push_back(syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_UPDATE,
- sync_data));
+ DCHECK_EQ(applied_sync_turl->keyword(), unapplied_sync_turl->keyword());
+ DCHECK(!applied_sync_turl->IsExtensionKeyword());
+
+ // Both |unapplied_sync_turl| and |applied_sync_turl| are known to Sync, so
+ // don't delete either of them. Instead, determine which is "better" and
+ // uniquify the other one, sending an update to the server for the updated
+ // entry.
+ const bool applied_turl_is_better =
+ IsLocalTemplateURLBetter(applied_sync_turl, unapplied_sync_turl);
+ TemplateURL* loser = applied_turl_is_better ?
+ unapplied_sync_turl : applied_sync_turl;
+ string16 new_keyword = UniquifyKeyword(*loser, false);
+ DCHECK(!GetTemplateURLForKeyword(new_keyword));
+ if (applied_turl_is_better) {
+ // Just set the keyword of |unapplied_sync_turl|. The caller is responsible
+ // for adding or updating unapplied_sync_turl in the local model.
+ unapplied_sync_turl->data_.SetKeyword(new_keyword);
} else {
- string16 new_keyword = UniquifyKeyword(*local_turl, false);
- TemplateURLData data(local_turl->data());
+ // Update |applied_sync_turl| in the local model with the new keyword.
+ TemplateURLData data(applied_sync_turl->data());
data.SetKeyword(new_keyword);
- TemplateURL new_turl(local_turl->profile(), data);
- UIThreadSearchTermsData search_terms_data(local_turl->profile());
- if (UpdateNoNotify(local_turl, new_turl, search_terms_data))
+ TemplateURL new_turl(applied_sync_turl->profile(), data);
+ UIThreadSearchTermsData search_terms_data(applied_sync_turl->profile());
+ if (UpdateNoNotify(applied_sync_turl, new_turl, search_terms_data))
NotifyObservers();
- // Since we're processing sync changes, the UpdateNoNotify() above didn't
- // generate an ACTION_UPDATE. We need to do it manually to keep the server
- // in sync with us. Note that if we're being called from
- // MergeDataAndStartSyncing(), and this TemplateURL was pre-existing rather
- // than having just been brought down, then this is wrong, because the
- // server won't know about this entity until it processes the ACTION_ADD our
- // caller will later generate; but in this case, PruneSyncChanges() will
- // prune out the ACTION_UPDATE we create here.
- syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
- change_list->push_back(syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_UPDATE,
- sync_data));
}
- return true;
-}
-
-TemplateURL* TemplateURLService::FindDuplicateOfSyncTemplateURL(
- const TemplateURL& sync_turl) {
- TemplateURL* existing_turl = GetTemplateURLForKeyword(sync_turl.keyword());
- return existing_turl && (existing_turl->url() == sync_turl.url()) ?
- existing_turl : NULL;
+ // The losing TemplateURL should have their keyword updated. Send a change to
+ // the server to reflect this change.
+ syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*loser);
+ change_list->push_back(syncer::SyncChange(FROM_HERE,
+ syncer::SyncChange::ACTION_UPDATE,
+ sync_data));
}
-void TemplateURLService::MergeSyncAndLocalURLDuplicates(
+void TemplateURLService::MergeInSyncTemplateURL(
TemplateURL* sync_turl,
- TemplateURL* local_turl,
- syncer::SyncChangeList* change_list) {
- DCHECK(loaded_);
+ const SyncDataMap& sync_data,
+ syncer::SyncChangeList* change_list,
+ SyncDataMap* local_data) {
DCHECK(sync_turl);
- DCHECK(local_turl);
- DCHECK(change_list);
- scoped_ptr<TemplateURL> scoped_sync_turl(sync_turl);
- if (sync_turl->last_modified() > local_turl->last_modified()) {
- // Fully replace local_url with Sync's copy. Note that because use Add
- // rather than ResetTemplateURL, |sync_url| is added with a fresh
- // TemplateURLID. We don't need to sync the new ID back to the server since
- // it's only relevant locally.
- bool delete_default = (local_turl == GetDefaultSearchProvider());
- DCHECK(!delete_default || !is_default_search_managed_);
- if (delete_default)
- default_search_provider_ = NULL;
-
- // See comments in ResolveSyncKeywordConflict() regarding generating an
- // ACTION_DELETE manually since Remove() won't do it.
- syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
- change_list->push_back(syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_DELETE,
- sync_data));
- Remove(local_turl);
+ DCHECK(!GetTemplateURLForGUID(sync_turl->sync_guid()));
+ DCHECK(IsFromSync(sync_turl, sync_data));
+
+ TemplateURL* conflicting_turl =
+ FindNonExtensionTemplateURLForKeyword(sync_turl->keyword());
+ bool should_add_sync_turl = true;
+
+ // If there was no TemplateURL in the local model that conflicts with
+ // |sync_turl|, skip the following preparation steps and just add |sync_turl|
+ // directly. Otherwise, modify |conflicting_turl| to make room for
+ // |sync_turl|.
+ if (conflicting_turl) {
+ if (IsFromSync(conflicting_turl, sync_data)) {
+ // |conflicting_turl| is already known to Sync, so we're not allowed to
+ // remove it. In this case, we want to uniquify the worse one and send an
+ // update for the changed keyword to sync. We can reuse the logic from
+ // ResolveSyncKeywordConflict for this.
+ ResolveSyncKeywordConflict(sync_turl, conflicting_turl, change_list);
+ } else {
+ // |conflicting_turl| is not yet known to Sync. If it is better, then we
+ // want to transfer its values up to sync. Otherwise, we remove it and
+ // allow the entry from Sync to overtake it in the model.
+ const std::string guid = conflicting_turl->sync_guid();
+ if (IsLocalTemplateURLBetter(conflicting_turl, sync_turl)) {
+ ResetTemplateURLGUID(conflicting_turl, sync_turl->sync_guid());
+ syncer::SyncData sync_data =
+ CreateSyncDataFromTemplateURL(*conflicting_turl);
+ change_list->push_back(syncer::SyncChange(
+ FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data));
+ if (conflicting_turl == GetDefaultSearchProvider() &&
+ !pending_synced_default_search_) {
+ // If we're not waiting for the Synced default to come in, we should
+ // override the pref with our new GUID. If we are waiting for the
+ // arrival of a synced default, setting the pref here would cause us
+ // to lose the GUID we are waiting on.
+ PrefService* prefs = GetPrefs();
+ if (prefs) {
+ prefs->SetString(prefs::kSyncedDefaultSearchProviderGUID,
+ conflicting_turl->sync_guid());
+ }
+ }
+ // Note that in this case we do not add the Sync TemplateURL to the
+ // local model, since we've effectively "merged" it in by updating the
+ // local conflicting entry with its sync_guid.
+ should_add_sync_turl = false;
+ } else {
+ // We guarantee that this isn't the local search provider. Otherwise,
+ // local would have won.
+ DCHECK(conflicting_turl != GetDefaultSearchProvider());
+ Remove(conflicting_turl);
+ }
+ // This TemplateURL was either removed or overwritten in the local model.
+ // Remove the entry from the local data so it isn't pushed up to Sync.
+ local_data->erase(guid);
+ }
+ }
+ if (should_add_sync_turl) {
+ const std::string guid = sync_turl->sync_guid();
// Force the local ID to kInvalidTemplateURLID so we can add it.
- sync_turl->data_.id = kInvalidTemplateURLID;
- Add(scoped_sync_turl.release());
- if (delete_default)
- SetDefaultSearchProvider(sync_turl);
- } else {
- // Change the local TURL's GUID to the server's GUID and push an update to
- // Sync. This ensures that the rest of local_url's fields are sync'd up to
- // the server, and the next time local_url is synced, it is recognized by
- // having the same GUID.
- ResetTemplateURLGUID(local_turl, sync_turl->sync_guid());
- syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
- change_list->push_back(syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_UPDATE,
- sync_data));
+ TemplateURLData data(sync_turl->data());
+ data.id = kInvalidTemplateURLID;
+ Add(new TemplateURL(profile_, data));
+
+ // Possibly set the newly added |turl| as the default search provider.
+ SetDefaultSearchProviderIfNewlySynced(guid);
}
}

Powered by Google App Engine
This is Rietveld 408576698