Commit 70e3528f authored by Tommy Li's avatar Tommy Li Committed by Commit Bot

[search_engines] Make TemplateURLService keyword map a std::multimap.

In the new world where we are no longer uniquifying keywords, and
instead tolerating multiple engines with the same keyword (we pretty
much have to), it's more convenient for us to use an std::multimap to
map keywords to engines rather than use std::map.

This is to unblock a few ideas I have:

 - Currently, to detect conflicts between engines, we traverse through
   the whole list of TemplateURLs during Add() and Update(). During
   startup and Sync, when we are adding a bunch of these engines, that
   makes the whole process O(n^2). I'd like to use this multimap to
   remove those loops (in a future CL).

 - Although it SEEMS like we may no longer need to detect conflicts in
   the new world of tolerating conflicts, that's not true. We still
   want to remove replaceable conflicting engines, and so we still want
   to detect them.

 - I also hope the multimap will enable me to unify and simplify the
   currently complicated logic that does the removal of replaceable
   conflicting engines.

 - Finally, I think the multimap won't be expensive to retrieve the
   "best" engine for any given keyword, since the typical number of
   values we linearly go through per keyword is going to be one to
   three... definitely single digits. Multimaps don't sort on value.

These things are going to be in followup CLs that are enabled by the
multimap.

See also:
https://chromium-review.googlesource.com/c/chromium/src/+/2519775

Bug: 1022775
Change-Id: I631ea6c3cf442736273e23fcda15f72095dca28a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2530801
Commit-Queue: Tommy Li <tommycli@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#826545}
parent 0ecc025d
...@@ -398,9 +398,19 @@ TemplateURL* TemplateURLService::GetTemplateURLForKeyword( ...@@ -398,9 +398,19 @@ TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
const TemplateURL* TemplateURLService::GetTemplateURLForKeyword( const TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
const base::string16& keyword) const { const base::string16& keyword) const {
auto elem(keyword_to_turl_and_length_.find(keyword)); // Finds and returns the best match for |keyword|.
if (elem != keyword_to_turl_and_length_.end()) const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
return elem->second.first; if (match_range.first != match_range.second) {
// Among the matches for |keyword| in the multimap, return the best one.
return std::min_element(
match_range.first, match_range.second,
[](const auto& a, const auto& b) {
return a.second.first
->IsBetterThanEngineWithConflictingKeyword(b.second.first);
})
->second.first;
}
return (!loaded_ && initial_default_search_provider_ && return (!loaded_ && initial_default_search_provider_ &&
(initial_default_search_provider_->keyword() == keyword)) (initial_default_search_provider_->keyword() == keyword))
? initial_default_search_provider_.get() ? initial_default_search_provider_.get()
...@@ -1080,7 +1090,6 @@ base::Optional<syncer::ModelError> TemplateURLService::ProcessSyncChanges( ...@@ -1080,7 +1090,6 @@ base::Optional<syncer::ModelError> TemplateURLService::ProcessSyncChanges(
MaybeUpdateDSEViaPrefs(existing_turl); MaybeUpdateDSEViaPrefs(existing_turl);
} }
// If something went wrong, we want to prematurely exit to avoid pushing // If something went wrong, we want to prematurely exit to avoid pushing
// inconsistent data to Sync. We return the last error we received. // inconsistent data to Sync. We return the last error we received.
if (error.IsSet()) if (error.IsSet())
...@@ -1462,28 +1471,15 @@ void TemplateURLService::Init(const Initializer* initializers, ...@@ -1462,28 +1471,15 @@ void TemplateURLService::Init(const Initializer* initializers,
void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) { void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) {
const base::string16& keyword = template_url->keyword(); const base::string16& keyword = template_url->keyword();
auto iter = keyword_to_turl_and_length_.find(keyword);
CHECK(iter != keyword_to_turl_and_length_.end()); // Remove from |keyword_to_turl_and_length_|. No need to find the best
// The entry at |iter| may not be |template_url| if it's an extension-created // fallback. We choose the best one as-needed from the multimap.
// entry with the same keyword. const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
if (iter->second.first == template_url) { for (auto it = match_range.first; it != match_range.second;) {
// We need to check whether the keyword can now be provided by another if (it->second.first == template_url) {
// TemplateURL. See the comments for BestEngineForKeyword() for more it = keyword_to_turl_and_length_.erase(it);
// information on extension keywords and how they can coexist with
// non-extension keywords.
TemplateURL* best_fallback = nullptr;
for (const auto& turl : template_urls_) {
if ((turl.get() != template_url) && (turl->keyword() == keyword)) {
if (!best_fallback ||
turl->IsBetterThanEngineWithConflictingKeyword(best_fallback)) {
best_fallback = turl.get();
}
}
}
if (best_fallback) {
AddToMap(best_fallback);
} else { } else {
keyword_to_turl_and_length_.erase(iter); ++it;
} }
} }
...@@ -1499,22 +1495,13 @@ void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) { ...@@ -1499,22 +1495,13 @@ void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) {
} }
void TemplateURLService::AddToMaps(TemplateURL* template_url) { void TemplateURLService::AddToMaps(TemplateURL* template_url) {
bool template_url_is_omnibox_api =
template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
const base::string16& keyword = template_url->keyword(); const base::string16& keyword = template_url->keyword();
KeywordToTURLAndMeaningfulLength::const_iterator i = keyword_to_turl_and_length_.insert(std::make_pair(
keyword_to_turl_and_length_.find(keyword); keyword,
if (i == keyword_to_turl_and_length_.end()) { TURLAndMeaningfulLength(
AddToMap(template_url); template_url, GetMeaningfulKeywordLength(keyword, template_url))));
} else {
TemplateURL* existing_url = i->second.first;
CHECK_NE(existing_url, template_url);
if (template_url->IsBetterThanEngineWithConflictingKeyword(existing_url)) {
AddToMap(template_url);
}
}
if (template_url_is_omnibox_api) if (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)
return; return;
if (!template_url->sync_guid().empty()) if (!template_url->sync_guid().empty())
...@@ -1524,13 +1511,6 @@ void TemplateURLService::AddToMaps(TemplateURL* template_url) { ...@@ -1524,13 +1511,6 @@ void TemplateURLService::AddToMaps(TemplateURL* template_url) {
provider_map_->Add(template_url, search_terms_data()); provider_map_->Add(template_url, search_terms_data());
} }
void TemplateURLService::AddToMap(TemplateURL* template_url) {
const base::string16& keyword = template_url->keyword();
keyword_to_turl_and_length_[keyword] =
TURLAndMeaningfulLength(
template_url, GetMeaningfulKeywordLength(keyword, template_url));
}
void TemplateURLService::SetTemplateURLs( void TemplateURLService::SetTemplateURLs(
std::unique_ptr<OwnedTemplateURLVector> urls) { std::unique_ptr<OwnedTemplateURLVector> urls) {
Scoper scoper(this); Scoper scoper(this);
......
...@@ -144,7 +144,8 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -144,7 +144,8 @@ class TemplateURLService : public WebDataServiceConsumer,
// Adds to |matches| all TemplateURLs whose keywords begin with |prefix|, // Adds to |matches| all TemplateURLs whose keywords begin with |prefix|,
// sorted shortest-keyword-first. If |supports_replacement_only| is true, only // sorted shortest-keyword-first. If |supports_replacement_only| is true, only
// TemplateURLs that support replacement are returned. // TemplateURLs that support replacement are returned. This method must be
// efficient, since it's run roughly once per omnibox keystroke.
void AddMatchingKeywords(const base::string16& prefix, void AddMatchingKeywords(const base::string16& prefix,
bool supports_replacement_only, bool supports_replacement_only,
TURLsAndMeaningfulLengths* matches); TURLsAndMeaningfulLengths* matches);
...@@ -461,11 +462,14 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -461,11 +462,14 @@ class TemplateURLService : public WebDataServiceConsumer,
using GUIDToTURL = std::map<std::string, TemplateURL*>; using GUIDToTURL = std::map<std::string, TemplateURL*>;
// A mapping from keywords to the corresponding TemplateURLs and their // A mapping from keywords to the corresponding TemplateURLs and their
// meaningful keyword lengths. A keyword can appear only once here because // meaningful keyword lengths. This is a multimap, so the system can
// there can be only one active TemplateURL associated with a given keyword. // efficiently tolerate multiple engines with the same keyword, like from
// extensions. The values are not sorted from best to worst for each keyword,
// since multimaps don't sort on value. Users that want the best value for
// each key must traverse through all matching items, but we expect there to
// be below three values per key.
using KeywordToTURLAndMeaningfulLength = using KeywordToTURLAndMeaningfulLength =
std::map<base::string16, TURLAndMeaningfulLength>; std::multimap<base::string16, TURLAndMeaningfulLength>;
// Declaration of values to be used in an enumerated histogram to tally // Declaration of values to be used in an enumerated histogram to tally
// changes to the default search provider from various entry points. In // changes to the default search provider from various entry points. In
// particular, we use this to see what proportion of changes are from Sync // particular, we use this to see what proportion of changes are from Sync
...@@ -530,7 +534,6 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -530,7 +534,6 @@ class TemplateURLService : public WebDataServiceConsumer,
void ApplyDefaultSearchChange(const TemplateURLData* new_dse_data, void ApplyDefaultSearchChange(const TemplateURLData* new_dse_data,
DefaultSearchManager::Source source); DefaultSearchManager::Source source);
// Applies a DSE change. May be called at startup or after transitioning to // Applies a DSE change. May be called at startup or after transitioning to
// the loaded state. Returns true if a change actually occurred. // the loaded state. Returns true if a change actually occurred.
bool ApplyDefaultSearchChangeNoMetrics(const TemplateURLData* new_dse_data, bool ApplyDefaultSearchChangeNoMetrics(const TemplateURLData* new_dse_data,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment