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

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

Issue 10806065: 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: Initial draft Created 8 years, 5 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 928525a0fd9e8949461ebc80f6eee449068fe468..46c31d1211907e39b1f759fa7fdc0daf1ed207e8 100644
--- a/chrome/browser/search_engines/template_url_service.cc
+++ b/chrome/browser/search_engines/template_url_service.cc
@@ -191,6 +191,14 @@ std::string OldBaseURLSearchTermsData::GoogleBaseURLValue() const {
return old_base_url;
}
+// Returns true if |turl|'s GUID is not found inside |sync_data|. We use this
+// 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, SyncDataMap& sync_data) {
+ return (sync_data.find(turl->sync_guid()) != sync_data.end());
+}
+
} // namespace
@@ -997,17 +1005,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.
+ ResolveSyncKeywordConflict2(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.";
@@ -1017,16 +1027,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.
+ ResolveSyncKeywordConflict2(turl.get(), existing_keyword_turl,
+ &new_changes);
}
UIThreadSearchTermsData search_terms_data(existing_turl->profile());
if (UpdateNoNotify(existing_turl, *turl, search_terms_data))
@@ -1114,6 +1119,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.
@@ -1144,27 +1150,11 @@ syncer::SyncError TemplateURLService::MergeDataAndStartSyncing(
// 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);
+ sync_data_map, &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);
- }
+ MergeInSyncTemplateURL(sync_turl.get(), sync_data_map, &new_changes,
Nicolas Zea 2012/07/23 20:20:52 given that this method supports finding a conflict
SteveT 2012/07/23 21:07:00 So the above method (MergeSyncAndLocalURLDuplicate
Nicolas Zea 2012/07/23 22:14:44 How is the behavior between the two different? It
SteveT 2012/07/24 14:46:30 Actually yeah, MergeInSyncTemplateURL is sort of a
+ &local_data_map);
}
}
}
@@ -2309,6 +2299,131 @@ string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl,
return keyword_candidate;
}
+// Find the "better" TemplateURL based on a set of heuristics:
+// * newer last_modified timestamp.
+// * ...
+// Returns true if |turl1| is better, false otherwise. In the case of ties,
+// prefer |turl1| (return true).
+bool CompareTemplateURLs(const TemplateURL* turl1, const TemplateURL* turl2) {
+ return false;
+}
+
+void TemplateURLService::MergeInSyncTemplateURL(
+ TemplateURL* sync_turl,
+ SyncDataMap& sync_data,
+ syncer::SyncChangeList* change_list,
+ SyncDataMap* initial_data) {
+ DCHECK(sync_turl);
+ DCHECK(!GetTemplateURLForGUID(sync_turl->sync_guid()));
+ DCHECK(IsFromSync(sync_turl, sync_data));
+
+ TemplateURL* local_turl =
+ FindNonExtensionTemplateURLForKeyword(sync_turl->keyword());
+ bool should_add_sync_turl = local_turl == NULL;
+
+ // If there was no TemplateURL in the local model that conflicts with
+ // |sync_turl|, we can skip the following preparation steps and just
+ // |sync_turl| directly.
+ if (!should_add_sync_turl) {
+ DCHECK(local_turl);
+ const bool local_is_better =
+ (local_turl->last_modified() > sync_turl->last_modified()) ||
+ local_turl->created_by_policy() ||
+ (local_turl == GetDefaultSearchProvider());
+ if (IsFromSync(local_turl, sync_data)) {
+ // |local_turl| was merged in earlier from 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
+ // ResolveSyncKeywordConflict2 for this.
+ ResolveSyncKeywordConflict2(sync_turl, local_turl, change_list);
+ should_add_sync_turl = true;
+ } else {
+ // |local_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.
+ if (local_is_better) {
+ 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));
+ // Note that in this case we do not set |should_add_sync_turl|, since
+ // we've effectively "merged" it in by updating the local entry with
+ // its sync_guid.
+ // TODO(stevet/reviewer): If local_turl was the DSP, should we set the
+ // Synced GUID pref with the new GUID? What about in
Nicolas Zea 2012/07/23 20:20:52 Hmm, interesting. Preferences are associated befor
SteveT 2012/07/23 21:07:00 Oh, so we have an ordering guarantee now that Pref
Nicolas Zea 2012/07/23 22:14:44 Yeah...it's not a guarantee, given that preference
SteveT 2012/07/24 14:46:30 So the problem here isn't the local_turl losing co
Nicolas Zea 2012/07/24 19:31:47 Ah, I see. So we're in one of two states: 1) We lo
SteveT 2012/07/24 21:51:18 Yes, so in (1), pending_synced_default_change_ is
Nicolas Zea 2012/07/24 22:13:37 I don't think we should be attempting to repair an
+ // MergeSyncAndLocalURLDuplicates, where we do something similar?
+ } else {
+ // We guarantee that this isn't the local search provider. Otherwise,
+ // local would have won.
+ DCHECK(local_turl != GetDefaultSearchProvider());
+ const std::string guid = local_turl->sync_guid();
+ Remove(local_turl);
+ // Also remove the entry from the initial data so that we don't push it
+ // up to Sync.
+ initial_data->erase(guid);
Nicolas Zea 2012/07/23 20:20:52 does this need to be done for the case above as we
SteveT 2012/07/23 21:07:00 Hm, yes, you're right. In either case, since local
+ should_add_sync_turl = true;
+ }
+ }
+ }
+
+ if (should_add_sync_turl) {
+ const std::string guid = sync_turl->sync_guid();
+ // 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.
+ // TODO(stevet/reviewer): Note that if this call notices a Default change,
+ // it will NOT set the pref since we are currently proccessing sync changes.
+ // See SetDefaultSearchProviderNoNotify.
+ // We might have to detect that case ourselves and explicitly set the pref?
Nicolas Zea 2012/07/23 20:20:52 I'm not sure I follow; why would we want to update
SteveT 2012/07/23 21:07:00 Ah right, I was thinking about just SetDefaultSear
+ SetDefaultSearchProviderIfNewlySynced(guid);
+ }
+}
+
+void TemplateURLService::ResolveSyncKeywordConflict2(
+ TemplateURL* sync_turl,
+ TemplateURL* local_turl,
Nicolas Zea 2012/07/23 20:20:52 |sync_turl| and |local_turl| don't really make sen
SteveT 2012/07/23 21:07:00 This is true, but local_turl is already located on
Nicolas Zea 2012/07/23 22:14:44 maybe unapplied_sync_turl and applied_sync_turl?
SteveT 2012/07/24 14:46:30 Sounds good. Done.
+ syncer::SyncChangeList* change_list) {
+ DCHECK(loaded_);
+ DCHECK(sync_turl);
+ DCHECK(local_turl);
+ DCHECK(change_list);
+ DCHECK(local_turl->keyword() == sync_turl->keyword());
+ DCHECK(!local_turl->IsExtensionKeyword());
+
+ // Both |sync_turl| and |local_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 local_is_better =
+ (local_turl->last_modified() > sync_turl->last_modified()) ||
+ local_turl->created_by_policy() ||
+ (local_turl == GetDefaultSearchProvider());
+ TemplateURL* loser = local_is_better ? local_turl : sync_turl;
+ string16 new_keyword = UniquifyKeyword(*loser, false);
+ DCHECK(!GetTemplateURLForKeyword(new_keyword));
+ syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*loser);
+ change_list->push_back(syncer::SyncChange(FROM_HERE,
+ syncer::SyncChange::ACTION_UPDATE,
+ sync_data));
+ if (local_is_better) {
+ // Just set the keyword of |sync_turl|. The caller is responsible for adding
+ // or updating sync_turl in the local model.
+ sync_turl->data_.SetKeyword(new_keyword);
+ } else {
+ // Update |local_turl| in the local model with the new keyword.
+ TemplateURLData data(local_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))
+ NotifyObservers();
+ }
+}
+
bool TemplateURLService::ResolveSyncKeywordConflict(
TemplateURL* sync_turl,
TemplateURL* local_turl,
@@ -2316,9 +2431,9 @@ bool TemplateURLService::ResolveSyncKeywordConflict(
DCHECK(loaded_);
DCHECK(sync_turl);
DCHECK(local_turl);
+ DCHECK(change_list);
DCHECK(sync_turl->sync_guid() != local_turl->sync_guid());
DCHECK(!local_turl->IsExtensionKeyword());
- DCHECK(change_list);
const bool local_is_better =
(local_turl->last_modified() > sync_turl->last_modified()) ||
@@ -2389,6 +2504,7 @@ TemplateURL* TemplateURLService::FindDuplicateOfSyncTemplateURL(
void TemplateURLService::MergeSyncAndLocalURLDuplicates(
TemplateURL* sync_turl,
TemplateURL* local_turl,
+ SyncDataMap& sync_data,
syncer::SyncChangeList* change_list) {
DCHECK(loaded_);
DCHECK(sync_turl);
@@ -2407,10 +2523,12 @@ void TemplateURLService::MergeSyncAndLocalURLDuplicates(
// 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));
+ if (IsFromSync(local_turl, sync_data)) {
Nicolas Zea 2012/07/23 20:20:52 I don't think we want to delete the local turl if
SteveT 2012/07/23 21:07:00 Hm yeah, this is actually wrong. What happens und
Nicolas Zea 2012/07/23 22:14:44 Yeah, I think that's the right approach.
SteveT 2012/07/24 14:46:30 Oops, when I said "roll the logic into ResolveSync
+ syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
+ change_list->push_back(syncer::SyncChange(FROM_HERE,
+ syncer::SyncChange::ACTION_DELETE,
+ sync_data));
+ }
Remove(local_turl);
// Force the local ID to kInvalidTemplateURLID so we can add it.

Powered by Google App Engine
This is Rietveld 408576698