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. |