| Index: chrome/browser/autocomplete/network_action_predictor.cc
|
| diff --git a/chrome/browser/autocomplete/network_action_predictor.cc b/chrome/browser/autocomplete/network_action_predictor.cc
|
| deleted file mode 100644
|
| index 310200e906c537bdde98dbba818c35818225df10..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/autocomplete/network_action_predictor.cc
|
| +++ /dev/null
|
| @@ -1,513 +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 "chrome/browser/autocomplete/network_action_predictor.h"
|
| -
|
| -#include <math.h>
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/i18n/case_conversion.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/string_util.h"
|
| -#include "base/stringprintf.h"
|
| -#include "base/utf_string_conversions.h"
|
| -#include "chrome/browser/autocomplete/autocomplete.h"
|
| -#include "chrome/browser/autocomplete/autocomplete_match.h"
|
| -#include "chrome/browser/autocomplete/network_action_predictor_database.h"
|
| -#include "chrome/browser/history/history.h"
|
| -#include "chrome/browser/history/history_notifications.h"
|
| -#include "chrome/browser/history/in_memory_database.h"
|
| -#include "chrome/browser/prerender/prerender_field_trial.h"
|
| -#include "chrome/browser/prerender/prerender_manager.h"
|
| -#include "chrome/browser/prerender/prerender_manager_factory.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/common/chrome_notification_types.h"
|
| -#include "chrome/common/guid.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/notification_details.h"
|
| -#include "content/public/browser/notification_service.h"
|
| -#include "content/public/browser/notification_source.h"
|
| -
|
| -namespace {
|
| -
|
| -const float kConfidenceCutoff[] = {
|
| - 0.8f,
|
| - 0.5f
|
| -};
|
| -
|
| -const size_t kMinimumUserTextLength = 1;
|
| -const int kMinimumNumberOfHits = 3;
|
| -
|
| -COMPILE_ASSERT(arraysize(kConfidenceCutoff) ==
|
| - NetworkActionPredictor::LAST_PREDICT_ACTION,
|
| - ConfidenceCutoff_count_mismatch);
|
| -
|
| -enum DatabaseAction {
|
| - DATABASE_ACTION_ADD,
|
| - DATABASE_ACTION_UPDATE,
|
| - DATABASE_ACTION_DELETE_SOME,
|
| - DATABASE_ACTION_DELETE_ALL,
|
| - DATABASE_ACTION_COUNT
|
| -};
|
| -
|
| -bool IsAutocompleteMatchSearchType(const AutocompleteMatch& match) {
|
| - switch (match.type) {
|
| - // Matches using the user's default search engine.
|
| - case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED:
|
| - case AutocompleteMatch::SEARCH_HISTORY:
|
| - case AutocompleteMatch::SEARCH_SUGGEST:
|
| - // A match that uses a non-default search engine (e.g. for tab-to-search).
|
| - case AutocompleteMatch::SEARCH_OTHER_ENGINE:
|
| - return true;
|
| -
|
| - default:
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -}
|
| -
|
| -const int NetworkActionPredictor::kMaximumDaysToKeepEntry = 14;
|
| -
|
| -double NetworkActionPredictor::hit_weight_ = 1.0;
|
| -
|
| -NetworkActionPredictor::NetworkActionPredictor(Profile* profile)
|
| - : profile_(profile),
|
| - db_(new NetworkActionPredictorDatabase(profile)),
|
| - initialized_(false) {
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::Initialize, db_));
|
| -
|
| - // Request the in-memory database from the history to force it to load so it's
|
| - // available as soon as possible.
|
| - HistoryService* history_service =
|
| - profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| - if (history_service)
|
| - history_service->InMemoryDatabase();
|
| -
|
| - // Create local caches using the database as loaded. We will garbage collect
|
| - // rows from the caches and the database once the history service is
|
| - // available.
|
| - std::vector<NetworkActionPredictorDatabase::Row>* rows =
|
| - new std::vector<NetworkActionPredictorDatabase::Row>();
|
| - content::BrowserThread::PostTaskAndReply(
|
| - content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::GetAllRows, db_, rows),
|
| - base::Bind(&NetworkActionPredictor::CreateCaches, AsWeakPtr(),
|
| - base::Owned(rows)));
|
| -
|
| -}
|
| -
|
| -NetworkActionPredictor::~NetworkActionPredictor() {
|
| -}
|
| -
|
| -void NetworkActionPredictor::RegisterTransitionalMatches(
|
| - const string16& user_text,
|
| - const AutocompleteResult& result) {
|
| - if (user_text.length() < kMinimumUserTextLength)
|
| - return;
|
| - const string16 lower_user_text(base::i18n::ToLower(user_text));
|
| -
|
| - // Merge this in to an existing match if we already saw |user_text|
|
| - std::vector<TransitionalMatch>::iterator match_it =
|
| - std::find(transitional_matches_.begin(), transitional_matches_.end(),
|
| - lower_user_text);
|
| -
|
| - if (match_it == transitional_matches_.end()) {
|
| - TransitionalMatch transitional_match;
|
| - transitional_match.user_text = lower_user_text;
|
| - match_it = transitional_matches_.insert(transitional_matches_.end(),
|
| - transitional_match);
|
| - }
|
| -
|
| - for (AutocompleteResult::const_iterator it = result.begin();
|
| - it != result.end(); ++it) {
|
| - if (std::find(match_it->urls.begin(), match_it->urls.end(),
|
| - it->destination_url) == match_it->urls.end()) {
|
| - match_it->urls.push_back(it->destination_url);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void NetworkActionPredictor::ClearTransitionalMatches() {
|
| - transitional_matches_.clear();
|
| -}
|
| -
|
| -// Given a match, return a recommended action.
|
| -NetworkActionPredictor::Action NetworkActionPredictor::RecommendAction(
|
| - const string16& user_text,
|
| - const AutocompleteMatch& match) const {
|
| - bool is_in_db = false;
|
| - const double confidence = CalculateConfidence(user_text, match, &is_in_db);
|
| - DCHECK(confidence >= 0.0 && confidence <= 1.0);
|
| -
|
| - UMA_HISTOGRAM_BOOLEAN("NetworkActionPredictor.MatchIsInDb", is_in_db);
|
| -
|
| - if (is_in_db) {
|
| - // Multiple enties with the same URL are fine as the confidence may be
|
| - // different.
|
| - tracked_urls_.push_back(std::make_pair(match.destination_url, confidence));
|
| - UMA_HISTOGRAM_COUNTS_100("NetworkActionPredictor.Confidence",
|
| - confidence * 100);
|
| - }
|
| -
|
| - // Map the confidence to an action.
|
| - Action action = ACTION_NONE;
|
| - for (int i = 0; i < LAST_PREDICT_ACTION; ++i) {
|
| - if (confidence >= kConfidenceCutoff[i]) {
|
| - action = static_cast<Action>(i);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - // Downgrade prerender to preconnect if this is a search match or if omnibox
|
| - // prerendering is disabled. There are cases when Instant will not handle a
|
| - // search suggestion and in those cases it would be good to prerender the
|
| - // search results, however search engines have not been set up to correctly
|
| - // handle being prerendered and until they are we should avoid it.
|
| - // http://crbug.com/117495
|
| - if (action == ACTION_PRERENDER &&
|
| - (IsAutocompleteMatchSearchType(match) ||
|
| - !prerender::IsOmniboxEnabled(profile_))) {
|
| - action = ACTION_PRECONNECT;
|
| - }
|
| -
|
| - return action;
|
| -}
|
| -
|
| -// Return true if the suggestion type warrants a TCP/IP preconnection.
|
| -// i.e., it is now quite likely that the user will select the related domain.
|
| -// static
|
| -bool NetworkActionPredictor::IsPreconnectable(const AutocompleteMatch& match) {
|
| - return IsAutocompleteMatchSearchType(match);
|
| -}
|
| -
|
| -void NetworkActionPredictor::Shutdown() {
|
| - db_->OnPredictorDestroyed();
|
| -}
|
| -
|
| -void NetworkActionPredictor::Observe(
|
| - int type,
|
| - const content::NotificationSource& source,
|
| - const content::NotificationDetails& details) {
|
| - switch (type) {
|
| - case chrome::NOTIFICATION_HISTORY_URLS_DELETED: {
|
| - DCHECK(initialized_);
|
| - const content::Details<const history::URLsDeletedDetails>
|
| - urls_deleted_details =
|
| - content::Details<const history::URLsDeletedDetails>(details);
|
| - if (urls_deleted_details->all_history)
|
| - DeleteAllRows();
|
| - else
|
| - DeleteRowsWithURLs(urls_deleted_details->rows);
|
| - break;
|
| - }
|
| -
|
| - // This notification does not catch all instances of the user navigating
|
| - // from the Omnibox, but it does catch the cases where the dropdown is open
|
| - // and those are the events we're most interested in.
|
| - case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
|
| - DCHECK(initialized_);
|
| -
|
| - // TODO(dominich): This doesn't need to be synchronous. Investigate
|
| - // posting it as a task to be run later.
|
| - OnOmniboxOpenedUrl(*content::Details<AutocompleteLog>(details).ptr());
|
| - break;
|
| - }
|
| -
|
| - case chrome::NOTIFICATION_HISTORY_LOADED: {
|
| - DCHECK(!initialized_);
|
| - TryDeleteOldEntries(content::Details<HistoryService>(details).ptr());
|
| -
|
| - notification_registrar_.Remove(this,
|
| - chrome::NOTIFICATION_HISTORY_LOADED,
|
| - content::Source<Profile>(profile_));
|
| - break;
|
| - }
|
| -
|
| - default:
|
| - NOTREACHED() << "Unexpected notification observed.";
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void NetworkActionPredictor::OnOmniboxOpenedUrl(const AutocompleteLog& log) {
|
| - if (log.text.length() < kMinimumUserTextLength)
|
| - return;
|
| -
|
| - const AutocompleteMatch& match = log.result.match_at(log.selected_index);
|
| -
|
| - UMA_HISTOGRAM_BOOLEAN(
|
| - StringPrintf("Prerender.OmniboxNavigationsCouldPrerender_%.1f%s",
|
| - get_hit_weight(),
|
| - prerender::PrerenderManager::GetModeString()).c_str(),
|
| - prerender::IsOmniboxEnabled(profile_));
|
| -
|
| - const GURL& opened_url = match.destination_url;
|
| -
|
| - // If the Omnibox triggered a prerender but the URL doesn't match the one the
|
| - // user is navigating to, cancel the prerender.
|
| - prerender::PrerenderManager* prerender_manager =
|
| - prerender::PrerenderManagerFactory::GetForProfile(profile_);
|
| - // |prerender_manager| can be NULL in incognito mode or if prerendering is
|
| - // otherwise disabled.
|
| - if (prerender_manager && !prerender_manager->IsPrerendering(opened_url))
|
| - prerender_manager->CancelOmniboxPrerenders();
|
| -
|
| - const string16 lower_user_text(base::i18n::ToLower(log.text));
|
| -
|
| - BeginTransaction();
|
| - // Traverse transitional matches for those that have a user_text that is a
|
| - // prefix of |lower_user_text|.
|
| - for (std::vector<TransitionalMatch>::const_iterator it =
|
| - transitional_matches_.begin(); it != transitional_matches_.end();
|
| - ++it) {
|
| - if (!StartsWith(lower_user_text, it->user_text, true))
|
| - continue;
|
| -
|
| - // Add entries to the database for those matches.
|
| - for (std::vector<GURL>::const_iterator url_it = it->urls.begin();
|
| - url_it != it->urls.end(); ++url_it) {
|
| - DCHECK(it->user_text.length() >= kMinimumUserTextLength);
|
| - const DBCacheKey key = { it->user_text, *url_it };
|
| - const bool is_hit = (*url_it == opened_url);
|
| -
|
| - NetworkActionPredictorDatabase::Row row;
|
| - row.user_text = key.user_text;
|
| - row.url = key.url;
|
| -
|
| - DBCacheMap::iterator it = db_cache_.find(key);
|
| - if (it == db_cache_.end()) {
|
| - row.id = guid::GenerateGUID();
|
| - row.number_of_hits = is_hit ? 1 : 0;
|
| - row.number_of_misses = is_hit ? 0 : 1;
|
| -
|
| - AddRow(key, row);
|
| - } else {
|
| - DCHECK(db_id_cache_.find(key) != db_id_cache_.end());
|
| - row.id = db_id_cache_.find(key)->second;
|
| - row.number_of_hits = it->second.number_of_hits + (is_hit ? 1 : 0);
|
| - row.number_of_misses = it->second.number_of_misses + (is_hit ? 0 : 1);
|
| -
|
| - UpdateRow(it, row);
|
| - }
|
| - }
|
| - }
|
| - CommitTransaction();
|
| -
|
| - ClearTransitionalMatches();
|
| -
|
| - // Check against tracked urls and log accuracy for the confidence we
|
| - // predicted.
|
| - for (std::vector<std::pair<GURL, double> >::const_iterator it =
|
| - tracked_urls_.begin(); it != tracked_urls_.end();
|
| - ++it) {
|
| - if (opened_url == it->first) {
|
| - UMA_HISTOGRAM_COUNTS_100("NetworkActionPredictor.AccurateCount",
|
| - it->second * 100);
|
| - }
|
| - }
|
| - tracked_urls_.clear();
|
| -}
|
| -
|
| -void NetworkActionPredictor::DeleteOldIdsFromCaches(
|
| - history::URLDatabase* url_db,
|
| - std::vector<NetworkActionPredictorDatabase::Row::Id>* id_list) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - DCHECK(url_db);
|
| - DCHECK(id_list);
|
| - id_list->clear();
|
| - for (DBCacheMap::iterator it = db_cache_.begin(); it != db_cache_.end();) {
|
| - history::URLRow url_row;
|
| -
|
| - if ((url_db->GetRowForURL(it->first.url, &url_row) == 0) ||
|
| - ((base::Time::Now() - url_row.last_visit()).InDays() >
|
| - kMaximumDaysToKeepEntry)) {
|
| - const DBIdCacheMap::iterator id_it = db_id_cache_.find(it->first);
|
| - DCHECK(id_it != db_id_cache_.end());
|
| - id_list->push_back(id_it->second);
|
| - db_id_cache_.erase(id_it);
|
| - db_cache_.erase(it++);
|
| - } else {
|
| - ++it;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void NetworkActionPredictor::DeleteOldEntries(history::URLDatabase* url_db) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - DCHECK(!initialized_);
|
| -
|
| - std::vector<NetworkActionPredictorDatabase::Row::Id> ids_to_delete;
|
| - DeleteOldIdsFromCaches(url_db, &ids_to_delete);
|
| -
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::DeleteRows, db_,
|
| - ids_to_delete));
|
| -
|
| - // Register for notifications and set the |initialized_| flag.
|
| - notification_registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
|
| - content::Source<Profile>(profile_));
|
| - notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
|
| - content::Source<Profile>(profile_));
|
| - initialized_ = true;
|
| -}
|
| -
|
| -void NetworkActionPredictor::CreateCaches(
|
| - std::vector<NetworkActionPredictorDatabase::Row>* rows) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - DCHECK(!initialized_);
|
| - DCHECK(db_cache_.empty());
|
| - DCHECK(db_id_cache_.empty());
|
| -
|
| - for (std::vector<NetworkActionPredictorDatabase::Row>::const_iterator it =
|
| - rows->begin(); it != rows->end(); ++it) {
|
| - const DBCacheKey key = { it->user_text, it->url };
|
| - const DBCacheValue value = { it->number_of_hits, it->number_of_misses };
|
| - db_cache_[key] = value;
|
| - db_id_cache_[key] = it->id;
|
| - }
|
| -
|
| - // If the history service is ready, delete any old or invalid entries.
|
| - HistoryService* history_service =
|
| - profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| - if (!TryDeleteOldEntries(history_service)) {
|
| - // Wait for the notification that the history service is ready and the URL
|
| - // DB is loaded.
|
| - notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_LOADED,
|
| - content::Source<Profile>(profile_));
|
| - }
|
| -}
|
| -
|
| -bool NetworkActionPredictor::TryDeleteOldEntries(HistoryService* service) {
|
| - if (!service)
|
| - return false;
|
| -
|
| - history::URLDatabase* url_db = service->InMemoryDatabase();
|
| - if (!url_db)
|
| - return false;
|
| -
|
| - DeleteOldEntries(url_db);
|
| - return true;
|
| -}
|
| -
|
| -double NetworkActionPredictor::CalculateConfidence(
|
| - const string16& user_text,
|
| - const AutocompleteMatch& match,
|
| - bool* is_in_db) const {
|
| - const DBCacheKey key = { user_text, match.destination_url };
|
| -
|
| - *is_in_db = false;
|
| - if (user_text.length() < kMinimumUserTextLength)
|
| - return 0.0;
|
| -
|
| - const DBCacheMap::const_iterator iter = db_cache_.find(key);
|
| - if (iter == db_cache_.end())
|
| - return 0.0;
|
| -
|
| - *is_in_db = true;
|
| - return CalculateConfidenceForDbEntry(iter);
|
| -}
|
| -
|
| -double NetworkActionPredictor::CalculateConfidenceForDbEntry(
|
| - DBCacheMap::const_iterator iter) const {
|
| - const DBCacheValue& value = iter->second;
|
| - if (value.number_of_hits < kMinimumNumberOfHits)
|
| - return 0.0;
|
| -
|
| - const double number_of_hits = value.number_of_hits * hit_weight_;
|
| - return number_of_hits / (number_of_hits + value.number_of_misses);
|
| -}
|
| -
|
| -void NetworkActionPredictor::AddRow(
|
| - const DBCacheKey& key,
|
| - const NetworkActionPredictorDatabase::Row& row) {
|
| - if (!initialized_)
|
| - return;
|
| -
|
| - DBCacheValue value = { row.number_of_hits, row.number_of_misses };
|
| - db_cache_[key] = value;
|
| - db_id_cache_[key] = row.id;
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::AddRow, db_, row));
|
| -
|
| - UMA_HISTOGRAM_ENUMERATION("NetworkActionPredictor.DatabaseAction",
|
| - DATABASE_ACTION_ADD, DATABASE_ACTION_COUNT);
|
| -}
|
| -
|
| -void NetworkActionPredictor::UpdateRow(
|
| - DBCacheMap::iterator it,
|
| - const NetworkActionPredictorDatabase::Row& row) {
|
| - if (!initialized_)
|
| - return;
|
| -
|
| - DCHECK(it != db_cache_.end());
|
| - it->second.number_of_hits = row.number_of_hits;
|
| - it->second.number_of_misses = row.number_of_misses;
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::UpdateRow, db_, row));
|
| - UMA_HISTOGRAM_ENUMERATION("NetworkActionPredictor.DatabaseAction",
|
| - DATABASE_ACTION_UPDATE, DATABASE_ACTION_COUNT);
|
| -}
|
| -
|
| -void NetworkActionPredictor::DeleteAllRows() {
|
| - if (!initialized_)
|
| - return;
|
| -
|
| - db_cache_.clear();
|
| - db_id_cache_.clear();
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::DeleteAllRows, db_));
|
| - UMA_HISTOGRAM_ENUMERATION("NetworkActionPredictor.DatabaseAction",
|
| - DATABASE_ACTION_DELETE_ALL, DATABASE_ACTION_COUNT);
|
| -}
|
| -
|
| -void NetworkActionPredictor::DeleteRowsWithURLs(const history::URLRows& rows) {
|
| - if (!initialized_)
|
| - return;
|
| -
|
| - std::vector<NetworkActionPredictorDatabase::Row::Id> id_list;
|
| -
|
| - for (DBCacheMap::iterator it = db_cache_.begin(); it != db_cache_.end();) {
|
| - if (std::find_if(rows.begin(), rows.end(),
|
| - history::URLRow::URLRowHasURL(it->first.url)) != rows.end()) {
|
| - const DBIdCacheMap::iterator id_it = db_id_cache_.find(it->first);
|
| - DCHECK(id_it != db_id_cache_.end());
|
| - id_list.push_back(id_it->second);
|
| - db_id_cache_.erase(id_it);
|
| - db_cache_.erase(it++);
|
| - } else {
|
| - ++it;
|
| - }
|
| - }
|
| -
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::DeleteRows, db_, id_list));
|
| - UMA_HISTOGRAM_ENUMERATION("NetworkActionPredictor.DatabaseAction",
|
| - DATABASE_ACTION_DELETE_SOME, DATABASE_ACTION_COUNT);
|
| -}
|
| -
|
| -void NetworkActionPredictor::BeginTransaction() {
|
| - if (!initialized_)
|
| - return;
|
| -
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::BeginTransaction, db_));
|
| -}
|
| -
|
| -void NetworkActionPredictor::CommitTransaction() {
|
| - if (!initialized_)
|
| - return;
|
| -
|
| - content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
|
| - base::Bind(&NetworkActionPredictorDatabase::CommitTransaction, db_));
|
| -}
|
| -
|
| -NetworkActionPredictor::TransitionalMatch::TransitionalMatch() {
|
| -}
|
| -
|
| -NetworkActionPredictor::TransitionalMatch::~TransitionalMatch() {
|
| -}
|
|
|