history_backend.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// found in the LICENSE file.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/history/history_backend.h"
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <algorithm>
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <functional>
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <list>
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <map>
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <set>
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <vector>
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/basictypes.h"
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/bind.h"
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/compiler_specific.h"
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/files/file_enumerator.h"
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/memory/scoped_vector.h"
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/message_loop/message_loop.h"
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/metrics/histogram.h"
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/rand_util.h"
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/string_util.h"
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/time/time.h"
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/autocomplete/history_url_provider.h"
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/favicon/favicon_changed_details.h"
29197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "chrome/browser/history/download_row.h"
305d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
31c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
32d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "chrome/browser/history/page_usage_data.h"
3409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#include "chrome/browser/history/top_sites.h"
353c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch#include "chrome/browser/history/typed_url_syncable_service.h"
36591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#include "chrome/browser/history/visit_filter.h"
37d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "chrome/common/chrome_constants.h"
38d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "chrome/common/importer/imported_favicon_usage.h"
39591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#include "chrome/common/url_constants.h"
403c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch#include "components/favicon_base/select_favicon_frames.h"
41591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#include "components/history/core/browser/history_client.h"
42591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#include "grit/chromium_strings.h"
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "grit/generated_resources.h"
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "sql/error_delegate_util.h"
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "url/gurl.h"
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
48c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#if defined(OS_ANDROID)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
50f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)#endif
517242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using base::Time;
537242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciusing base::TimeDelta;
54197021e6b966cfb06891637935ef33fff06433d1Ben Murdochusing base::TimeTicks;
55521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* The HistoryBackend consists of two components:
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      URLDatabase (stores a list of URLs)
607242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      DownloadDatabase (stores a list of downloads)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
62d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ExpireHistoryBackend (manages deleting things older than 3 months)
65d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)*/
66d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
67d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)namespace history {
68d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
69d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// How long we keep segment data for in days. Currently 3 months.
70d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// This value needs to be greater or equal to
71d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
72d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// dependency between MostVisitedModel and the history backend.
73d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)const int kSegmentDataRetention = 90;
74d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
75d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
76d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)const int kCommitIntervalSeconds = 10;
77d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
78d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// The amount of time before we re-fetch the favicon.
79d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)const int kFaviconRefetchDays = 7;
80d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
81d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
82d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// deleting some.
83d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)const int kMaxRedirectCount = 32;
84d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
85d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
86d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// and is deleted.
877242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciconst int kExpireDaysThreshold = 90;
887242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
897242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#if defined(OS_ANDROID)
907242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// The maximum number of top sites to track when recording top page visit stats.
917242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciconst size_t kPageVisitStatsMaxTopSites = 50;
927242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#endif
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// Converts from PageUsageData to MostVisitedURL. |redirects| is a
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                  const RedirectList& redirects) {
987242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  MostVisitedURL mv;
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  mv.url = page_data.GetURL();
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  mv.title = page_data.GetTitle();
10102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch  if (redirects.empty()) {
102d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Redirects must contain at least the target url.
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mv.redirects.push_back(mv.url);
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  } else {
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mv.redirects = redirects;
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
107d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)      // The last url must be the target url.
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      mv.redirects.push_back(mv.url);
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return mv;
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
113d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// so they are batched together. The important thing about this class is that
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// to be one of these commits still pending and holding a reference.
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// task will still run (if we ever get to processing the event before
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// shutdown), but it will not do anything.
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
12553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)// be assigned to a RunnableMethod.
1267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci//
12709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
12809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
12909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// in ExpireHistoryBackend).
130f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
131f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) public:
132197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  explicit CommitLaterTask(HistoryBackend* history_backend)
133197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch      : history_backend_(history_backend) {
134197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  }
135197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
136197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  // The backend will call this function if it is being destroyed so that we
137197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  // release our reference.
138197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  void Cancel() {
139197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    history_backend_ = NULL;
140f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)  }
141d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
142d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)  void RunCommit() {
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (history_backend_.get())
144926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)      history_backend_->Commit();
145926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)  }
14609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
14709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) private:
14809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  ~CommitLaterTask() {}
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
1547242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// HistoryBackend::QueryURLResult ----------------------------------------------
1567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1577242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciHistoryBackend::QueryURLResult::QueryURLResult() : success(false) {
1587242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1597242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1607242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciHistoryBackend::QueryURLResult::~QueryURLResult() {
1617242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1637242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// HistoryBackend --------------------------------------------------------------
1647242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1657242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciHistoryBackend::HistoryBackend(const base::FilePath& history_dir,
1667242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci                               Delegate* delegate,
1677242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci                               HistoryClient* history_client)
1687242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    : delegate_(delegate),
1697242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      history_dir_(history_dir),
1707242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      scheduled_kill_db_(false),
1717242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      expirer_(this, history_client),
1727242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      recent_redirects_(kMaxRedirectCount),
1737242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      backend_destroy_message_loop_(NULL),
1747242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      segment_queried_(false),
1757242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci      history_client_(history_client) {
1767242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)HistoryBackend::~HistoryBackend() {
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
180f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)  ReleaseDBTasks();
1817242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if defined(OS_ANDROID)
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // Release AndroidProviderBackend before other objects.
1847242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  android_provider_backend_.reset();
1857242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#endif
1867242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
187926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
188926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)  CloseAllDatabases();
1891e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
190e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
191d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
192d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
1947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  }
1957242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1967242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#if defined(OS_ANDROID)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  sql::Connection::Delete(GetAndroidCacheFileName());
198197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#endif
1997242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
2007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
201197021e6b966cfb06891637935ef33fff06433d1Ben Murdochvoid HistoryBackend::Init(const std::string& languages, bool force_fail) {
2027242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  if (!force_fail)
203d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    InitImpl(languages);
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  delegate_->DBLoaded();
2053c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
2063c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch  memory_pressure_listener_.reset(new base::MemoryPressureListener(
2073c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
2085d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#if defined(OS_ANDROID)
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  PopulateMostVisitedURLMap();
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
2117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
2123c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch
2133c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdochvoid HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
214f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)                                             const base::Closure& task) {
215f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)  if (!backend_destroy_task_.is_null())
21609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
21709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
21809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  backend_destroy_task_ = task;
21909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
2207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
2217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid HistoryBackend::Closing() {
2227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  // Any scheduled commit will have a reference to us, we must make it
2237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  // release that reference before we can be destroyed.
2247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  CancelScheduledCommit();
2257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
2267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  // Release our reference to the delegate, this reference will be keeping the
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // history service alive.
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  delegate_.reset();
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void HistoryBackend::ClearCachedDataForContextID(ContextID context_id) {
232  tracker_.ClearCachedDataForContextID(context_id);
233}
234
235base::FilePath HistoryBackend::GetThumbnailFileName() const {
236  return history_dir_.Append(chrome::kThumbnailsFilename);
237}
238
239base::FilePath HistoryBackend::GetFaviconsFileName() const {
240  return history_dir_.Append(chrome::kFaviconsFilename);
241}
242
243base::FilePath HistoryBackend::GetArchivedFileName() const {
244  return history_dir_.Append(chrome::kArchivedHistoryFilename);
245}
246
247#if defined(OS_ANDROID)
248base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
249  return history_dir_.Append(chrome::kAndroidCacheFilename);
250}
251#endif
252
253SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
254  // Set is used to detect referrer loops.  Should not happen, but can
255  // if the database is corrupt.
256  std::set<VisitID> visit_set;
257  VisitID visit_id = from_visit;
258  while (visit_id) {
259    VisitRow row;
260    if (!db_->GetRowForVisit(visit_id, &row))
261      return 0;
262    if (row.segment_id)
263      return row.segment_id;  // Found a visit in this change with a segment.
264
265    // Check the referrer of this visit, if any.
266    visit_id = row.referring_visit;
267
268    if (visit_set.find(visit_id) != visit_set.end()) {
269      NOTREACHED() << "Loop in referer chain, giving up";
270      break;
271    }
272    visit_set.insert(visit_id);
273  }
274  return 0;
275}
276
277SegmentID HistoryBackend::UpdateSegments(
278    const GURL& url,
279    VisitID from_visit,
280    VisitID visit_id,
281    content::PageTransition transition_type,
282    const Time ts) {
283  if (!db_)
284    return 0;
285
286  // We only consider main frames.
287  if (!content::PageTransitionIsMainFrame(transition_type))
288    return 0;
289
290  SegmentID segment_id = 0;
291  content::PageTransition t =
292      content::PageTransitionStripQualifier(transition_type);
293
294  // Are we at the beginning of a new segment?
295  // Note that navigating to an existing entry (with back/forward) reuses the
296  // same transition type.  We are not adding it as a new segment in that case
297  // because if this was the target of a redirect, we might end up with
298  // 2 entries for the same final URL. Ex: User types google.net, gets
299  // redirected to google.com. A segment is created for google.net. On
300  // google.com users navigates through a link, then press back. That last
301  // navigation is for the entry google.com transition typed. We end up adding
302  // a segment for that one as well. So we end up with google.net and google.com
303  // in the segment table, showing as 2 entries in the NTP.
304  // Note also that we should still be updating the visit count for that segment
305  // which we are not doing now. It should be addressed when
306  // http://crbug.com/96860 is fixed.
307  if ((t == content::PAGE_TRANSITION_TYPED ||
308       t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
309      (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
310    // If so, create or get the segment.
311    std::string segment_name = db_->ComputeSegmentName(url);
312    URLID url_id = db_->GetRowForURL(url, NULL);
313    if (!url_id)
314      return 0;
315
316    if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
317      if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
318        NOTREACHED();
319        return 0;
320      }
321    } else {
322      // Note: if we update an existing segment, we update the url used to
323      // represent that segment in order to minimize stale most visited
324      // images.
325      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
326    }
327  } else {
328    // Note: it is possible there is no segment ID set for this visit chain.
329    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
330    // TYPED. (For example GENERATED). In this case this visit doesn't count
331    // toward any segment.
332    if (!(segment_id = GetLastSegmentID(from_visit)))
333      return 0;
334  }
335
336  // Set the segment in the visit.
337  if (!db_->SetSegmentID(visit_id, segment_id)) {
338    NOTREACHED();
339    return 0;
340  }
341
342  // Finally, increase the counter for that segment / day.
343  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
344    NOTREACHED();
345    return 0;
346  }
347  return segment_id;
348}
349
350void HistoryBackend::UpdateWithPageEndTime(ContextID context_id,
351                                           int32 page_id,
352                                           const GURL& url,
353                                           Time end_ts) {
354  // Will be filled with the URL ID and the visit ID of the last addition.
355  VisitID visit_id = tracker_.GetLastVisit(context_id, page_id, url);
356  UpdateVisitDuration(visit_id, end_ts);
357}
358
359void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
360  if (!db_)
361    return;
362
363  // Get the starting visit_time for visit_id.
364  VisitRow visit_row;
365  if (db_->GetRowForVisit(visit_id, &visit_row)) {
366    // We should never have a negative duration time even when time is skewed.
367    visit_row.visit_duration = end_ts > visit_row.visit_time ?
368        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
369    db_->UpdateVisitRow(visit_row);
370  }
371}
372
373void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
374  if (!db_)
375    return;
376
377  // Will be filled with the URL ID and the visit ID of the last addition.
378  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
379      request.context_id, request.page_id, request.referrer));
380
381  VisitID from_visit_id = last_ids.second;
382
383  // If a redirect chain is given, we expect the last item in that chain to be
384  // the final URL.
385  DCHECK(request.redirects.empty() ||
386         request.redirects.back() == request.url);
387
388  // If the user is adding older history, we need to make sure our times
389  // are correct.
390  if (request.time < first_recorded_time_)
391    first_recorded_time_ = request.time;
392
393  content::PageTransition request_transition = request.transition;
394  content::PageTransition stripped_transition =
395    content::PageTransitionStripQualifier(request_transition);
396  bool is_keyword_generated =
397      (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
398
399  // If the user is navigating to a not-previously-typed intranet hostname,
400  // change the transition to TYPED so that the omnibox will learn that this is
401  // a known host.
402  bool has_redirects = request.redirects.size() > 1;
403  if (content::PageTransitionIsMainFrame(request_transition) &&
404      (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
405      !is_keyword_generated) {
406    const GURL& origin_url(has_redirects ?
407        request.redirects[0] : request.url);
408    if (origin_url.SchemeIs(url::kHttpScheme) ||
409        origin_url.SchemeIs(url::kHttpsScheme) ||
410        origin_url.SchemeIs(url::kFtpScheme)) {
411      std::string host(origin_url.host());
412      size_t registry_length =
413          net::registry_controlled_domains::GetRegistryLength(
414              host,
415              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
416              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
417      if (registry_length == 0 && !db_->IsTypedHost(host)) {
418        stripped_transition = content::PAGE_TRANSITION_TYPED;
419        request_transition =
420            content::PageTransitionFromInt(
421                stripped_transition |
422                content::PageTransitionGetQualifier(request_transition));
423      }
424    }
425  }
426
427  if (!has_redirects) {
428    // The single entry is both a chain start and end.
429    content::PageTransition t = content::PageTransitionFromInt(
430        request_transition |
431        content::PAGE_TRANSITION_CHAIN_START |
432        content::PAGE_TRANSITION_CHAIN_END);
433
434    // No redirect case (one element means just the page itself).
435    last_ids = AddPageVisit(request.url, request.time,
436                            last_ids.second, t, request.visit_source);
437
438    // Update the segment for this visit. KEYWORD_GENERATED visits should not
439    // result in changing most visited, so we don't update segments (most
440    // visited db).
441    if (!is_keyword_generated) {
442      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
443                     request.time);
444
445      // Update the referrer's duration.
446      UpdateVisitDuration(from_visit_id, request.time);
447    }
448  } else {
449    // Redirect case. Add the redirect chain.
450
451    content::PageTransition redirect_info =
452        content::PAGE_TRANSITION_CHAIN_START;
453
454    RedirectList redirects = request.redirects;
455    if (redirects[0].SchemeIs(url::kAboutScheme)) {
456      // When the redirect source + referrer is "about" we skip it. This
457      // happens when a page opens a new frame/window to about:blank and then
458      // script sets the URL to somewhere else (used to hide the referrer). It
459      // would be nice to keep all these redirects properly but we don't ever
460      // see the initial about:blank load, so we don't know where the
461      // subsequent client redirect came from.
462      //
463      // In this case, we just don't bother hooking up the source of the
464      // redirects, so we remove it.
465      redirects.erase(redirects.begin());
466    } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
467      redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
468      // The first entry in the redirect chain initiated a client redirect.
469      // We don't add this to the database since the referrer is already
470      // there, so we skip over it but change the transition type of the first
471      // transition to client redirect.
472      //
473      // The referrer is invalid when restoring a session that features an
474      // https tab that redirects to a different host or to http. In this
475      // case we don't need to reconnect the new redirect with the existing
476      // chain.
477      if (request.referrer.is_valid()) {
478        DCHECK(request.referrer == redirects[0]);
479        redirects.erase(redirects.begin());
480
481        // If the navigation entry for this visit has replaced that for the
482        // first visit, remove the CHAIN_END marker from the first visit. This
483        // can be called a lot, for example, the page cycler, and most of the
484        // time we won't have changed anything.
485        VisitRow visit_row;
486        if (request.did_replace_entry &&
487            db_->GetRowForVisit(last_ids.second, &visit_row) &&
488            visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
489          visit_row.transition = content::PageTransitionFromInt(
490              visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
491          db_->UpdateVisitRow(visit_row);
492        }
493      }
494    }
495
496    for (size_t redirect_index = 0; redirect_index < redirects.size();
497         redirect_index++) {
498      content::PageTransition t =
499          content::PageTransitionFromInt(stripped_transition | redirect_info);
500
501      // If this is the last transition, add a CHAIN_END marker
502      if (redirect_index == (redirects.size() - 1)) {
503        t = content::PageTransitionFromInt(
504            t | content::PAGE_TRANSITION_CHAIN_END);
505      }
506
507      // Record all redirect visits with the same timestamp. We don't display
508      // them anyway, and if we ever decide to, we can reconstruct their order
509      // from the redirect chain.
510      last_ids = AddPageVisit(redirects[redirect_index],
511                              request.time, last_ids.second,
512                              t, request.visit_source);
513      if (t & content::PAGE_TRANSITION_CHAIN_START) {
514        // Update the segment for this visit.
515        UpdateSegments(redirects[redirect_index],
516                       from_visit_id, last_ids.second, t, request.time);
517
518        // Update the visit_details for this visit.
519        UpdateVisitDuration(from_visit_id, request.time);
520      }
521
522      // Subsequent transitions in the redirect list must all be server
523      // redirects.
524      redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
525    }
526
527    // Last, save this redirect chain for later so we can set titles & favicons
528    // on the redirected pages properly.
529    recent_redirects_.Put(request.url, redirects);
530  }
531
532  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
533  // views can keep in sync.
534
535  // Add the last visit to the tracker so we can get outgoing transitions.
536  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
537  // navigation anyway, so last_visit_id is always zero for them.  But adding
538  // them here confuses main frame history, so we skip them for now.
539  if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
540      stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
541      !is_keyword_generated) {
542    tracker_.AddVisit(request.context_id, request.page_id, request.url,
543                      last_ids.second);
544  }
545
546  ScheduleCommit();
547}
548
549void HistoryBackend::InitImpl(const std::string& languages) {
550  DCHECK(!db_) << "Initializing HistoryBackend twice";
551  // In the rare case where the db fails to initialize a dialog may get shown
552  // the blocks the caller, yet allows other messages through. For this reason
553  // we only set db_ to the created database if creation is successful. That
554  // way other methods won't do anything as db_ is still NULL.
555
556  TimeTicks beginning_time = TimeTicks::Now();
557
558  // Compute the file names.
559  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
560  base::FilePath thumbnail_name = GetFaviconsFileName();
561  base::FilePath archived_name = GetArchivedFileName();
562
563  // Delete the old index database files which are no longer used.
564  DeleteFTSIndexDatabases();
565
566  // History database.
567  db_.reset(new HistoryDatabase());
568
569  // Unretained to avoid a ref loop with db_.
570  db_->set_error_callback(
571      base::Bind(&HistoryBackend::DatabaseErrorCallback,
572                 base::Unretained(this)));
573
574  sql::InitStatus status = db_->Init(history_name);
575  switch (status) {
576    case sql::INIT_OK:
577      break;
578    case sql::INIT_FAILURE: {
579      // A NULL db_ will cause all calls on this object to notice this error
580      // and to not continue. If the error callback scheduled killing the
581      // database, the task it posted has not executed yet. Try killing the
582      // database now before we close it.
583      bool kill_db = scheduled_kill_db_;
584      if (kill_db)
585        KillHistoryDatabase();
586      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
587      delegate_->NotifyProfileError(status);
588      db_.reset();
589      return;
590    }
591    default:
592      NOTREACHED();
593  }
594
595  // Fill the in-memory database and send it back to the history service on the
596  // main thread.
597  {
598    scoped_ptr<InMemoryHistoryBackend> mem_backend(new InMemoryHistoryBackend);
599    if (mem_backend->Init(history_name, db_.get()))
600      delegate_->SetInMemoryBackend(mem_backend.Pass());
601  }
602  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
603
604  // Thumbnail database.
605  // TODO(shess): "thumbnail database" these days only stores
606  // favicons.  Thumbnails are stored in "top sites".  Consider
607  // renaming "thumbnail" references to "favicons" or something of the
608  // sort.
609  thumbnail_db_.reset(new ThumbnailDatabase());
610  if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) {
611    // Unlike the main database, we don't error out when the database is too
612    // new because this error is much less severe. Generally, this shouldn't
613    // happen since the thumbnail and main database versions should be in sync.
614    // We'll just continue without thumbnails & favicons in this case or any
615    // other error.
616    LOG(WARNING) << "Could not initialize the thumbnail database.";
617    thumbnail_db_.reset();
618  }
619
620  // Nuke any files corresponding to the legacy Archived History Database, which
621  // previously retained expired (> 3 months old) history entries, but, in the
622  // end, was not used for much, and consequently has been removed as of M37.
623  // TODO(engedy): Remove this code after the end of 2014.
624  sql::Connection::Delete(archived_name);
625
626  // Generate the history and thumbnail database metrics only after performing
627  // any migration work.
628  if (base::RandInt(1, 100) == 50) {
629    // Only do this computation sometimes since it can be expensive.
630    db_->ComputeDatabaseMetrics(history_name);
631    if (thumbnail_db_)
632      thumbnail_db_->ComputeDatabaseMetrics();
633  }
634
635  expirer_.SetDatabases(db_.get(), thumbnail_db_.get());
636
637  // Open the long-running transaction.
638  db_->BeginTransaction();
639  if (thumbnail_db_)
640    thumbnail_db_->BeginTransaction();
641
642  // Get the first item in our database.
643  db_->GetStartDate(&first_recorded_time_);
644
645  // Start expiring old stuff.
646  expirer_.StartExpiringOldStuff(TimeDelta::FromDays(kExpireDaysThreshold));
647
648#if defined(OS_ANDROID)
649  if (thumbnail_db_) {
650    android_provider_backend_.reset(
651        new AndroidProviderBackend(GetAndroidCacheFileName(),
652                                   db_.get(),
653                                   thumbnail_db_.get(),
654                                   history_client_,
655                                   delegate_.get()));
656  }
657#endif
658
659  HISTOGRAM_TIMES("History.InitTime",
660                  TimeTicks::Now() - beginning_time);
661}
662
663void HistoryBackend::OnMemoryPressure(
664    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
665  bool trim_aggressively = memory_pressure_level ==
666      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
667  if (db_)
668    db_->TrimMemory(trim_aggressively);
669  if (thumbnail_db_)
670    thumbnail_db_->TrimMemory(trim_aggressively);
671}
672
673void HistoryBackend::CloseAllDatabases() {
674  if (db_) {
675    // Commit the long-running transaction.
676    db_->CommitTransaction();
677    db_.reset();
678    // Forget the first recorded time since the database is closed.
679    first_recorded_time_ = base::Time();
680  }
681  if (thumbnail_db_) {
682    thumbnail_db_->CommitTransaction();
683    thumbnail_db_.reset();
684  }
685}
686
687std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
688    const GURL& url,
689    Time time,
690    VisitID referring_visit,
691    content::PageTransition transition,
692    VisitSource visit_source) {
693  // Top-level frame navigations are visible, everything else is hidden
694  bool new_hidden = !content::PageTransitionIsMainFrame(transition);
695
696  // NOTE: This code must stay in sync with
697  // ExpireHistoryBackend::ExpireURLsForVisits().
698  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
699  // typed, which would eliminate the need for this code.
700  int typed_increment = 0;
701  content::PageTransition transition_type =
702      content::PageTransitionStripQualifier(transition);
703  if ((transition_type == content::PAGE_TRANSITION_TYPED &&
704      !content::PageTransitionIsRedirect(transition)) ||
705      transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
706    typed_increment = 1;
707
708#if defined(OS_ANDROID)
709  // Only count the page visit if it came from user browsing and only count it
710  // once when cycling through a redirect chain.
711  if (visit_source == SOURCE_BROWSED &&
712      (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
713    RecordTopPageVisitStats(url);
714  }
715#endif
716
717  // See if this URL is already in the DB.
718  URLRow url_info(url);
719  URLID url_id = db_->GetRowForURL(url, &url_info);
720  if (url_id) {
721    // Update of an existing row.
722    if (content::PageTransitionStripQualifier(transition) !=
723        content::PAGE_TRANSITION_RELOAD)
724      url_info.set_visit_count(url_info.visit_count() + 1);
725    if (typed_increment)
726      url_info.set_typed_count(url_info.typed_count() + typed_increment);
727    if (url_info.last_visit() < time)
728      url_info.set_last_visit(time);
729
730    // Only allow un-hiding of pages, never hiding.
731    if (!new_hidden)
732      url_info.set_hidden(false);
733
734    db_->UpdateURLRow(url_id, url_info);
735  } else {
736    // Addition of a new row.
737    url_info.set_visit_count(1);
738    url_info.set_typed_count(typed_increment);
739    url_info.set_last_visit(time);
740    url_info.set_hidden(new_hidden);
741
742    url_id = db_->AddURL(url_info);
743    if (!url_id) {
744      NOTREACHED() << "Adding URL failed.";
745      return std::make_pair(0, 0);
746    }
747    url_info.id_ = url_id;
748  }
749
750  // Add the visit with the time to the database.
751  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
752  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
753  NotifyVisitObservers(visit_info);
754
755  if (visit_info.visit_time < first_recorded_time_)
756    first_recorded_time_ = visit_info.visit_time;
757
758  // Broadcast a notification of the visit.
759  if (visit_id) {
760    if (typed_url_syncable_service_.get())
761      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
762
763    scoped_ptr<URLVisitedDetails> details(new URLVisitedDetails);
764    details->transition = transition;
765    details->row = url_info;
766    details->visit_time = time;
767    // TODO(meelapshah) Disabled due to potential PageCycler regression.
768    // Re-enable this.
769    // GetMostRecentRedirectsTo(url, &details->redirects);
770    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED,
771                           details.PassAs<HistoryDetails>());
772  } else {
773    VLOG(0) << "Failed to build visit insert statement:  "
774            << "url_id = " << url_id;
775  }
776
777  return std::make_pair(url_id, visit_id);
778}
779
780void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
781                                         VisitSource visit_source) {
782  if (!db_)
783    return;
784
785  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
786  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
787    DCHECK(!i->last_visit().is_null());
788
789    // As of M37, we no longer maintain an archived database, ignore old visits.
790    if (IsExpiredVisitTime(i->last_visit()))
791      continue;
792
793    URLRow existing_url;
794    URLID url_id = db_->GetRowForURL(i->url(), &existing_url);
795    if (!url_id) {
796      // Add the page if it doesn't exist.
797      url_id = db_->AddURL(*i);
798      if (!url_id) {
799        NOTREACHED() << "Could not add row to DB";
800        return;
801      }
802
803      modified->changed_urls.push_back(*i);
804      modified->changed_urls.back().set_id(url_id);  // i->id_ is likely 0.
805    }
806
807    // Sync code manages the visits itself.
808    if (visit_source != SOURCE_SYNCED) {
809      // Make up a visit to correspond to the last visit to the page.
810      VisitRow visit_info(url_id, i->last_visit(), 0,
811                          content::PageTransitionFromInt(
812                              content::PAGE_TRANSITION_LINK |
813                              content::PAGE_TRANSITION_CHAIN_START |
814                              content::PAGE_TRANSITION_CHAIN_END), 0);
815      if (!db_->AddVisit(&visit_info, visit_source)) {
816        NOTREACHED() << "Adding visit failed.";
817        return;
818      }
819      NotifyVisitObservers(visit_info);
820
821      if (visit_info.visit_time < first_recorded_time_)
822        first_recorded_time_ = visit_info.visit_time;
823    }
824  }
825
826  if (typed_url_syncable_service_.get())
827    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
828
829  // Broadcast a notification for typed URLs that have been modified. This
830  // will be picked up by the in-memory URL database on the main thread.
831  //
832  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
833  // views can keep in sync.
834  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
835                         modified.PassAs<HistoryDetails>());
836
837  ScheduleCommit();
838}
839
840bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
841  return time < expirer_.GetCurrentExpirationTime();
842}
843
844void HistoryBackend::SetPageTitle(const GURL& url,
845                                  const base::string16& title) {
846  if (!db_)
847    return;
848
849  // Search for recent redirects which should get the same title. We make a
850  // dummy list containing the exact URL visited if there are no redirects so
851  // the processing below can be the same.
852  history::RedirectList dummy_list;
853  history::RedirectList* redirects;
854  RedirectCache::iterator iter = recent_redirects_.Get(url);
855  if (iter != recent_redirects_.end()) {
856    redirects = &iter->second;
857
858    // This redirect chain should have the destination URL as the last item.
859    DCHECK(!redirects->empty());
860    DCHECK(redirects->back() == url);
861  } else {
862    // No redirect chain stored, make up one containing the URL we want so we
863    // can use the same logic below.
864    dummy_list.push_back(url);
865    redirects = &dummy_list;
866  }
867
868  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
869  for (size_t i = 0; i < redirects->size(); i++) {
870    URLRow row;
871    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
872    if (row_id && row.title() != title) {
873      row.set_title(title);
874      db_->UpdateURLRow(row_id, row);
875      details->changed_urls.push_back(row);
876    }
877  }
878
879  // Broadcast notifications for any URLs that have changed. This will
880  // update the in-memory database and the InMemoryURLIndex.
881  if (!details->changed_urls.empty()) {
882    if (typed_url_syncable_service_.get())
883      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
884    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
885                           details.PassAs<HistoryDetails>());
886    ScheduleCommit();
887  }
888}
889
890void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
891                                               const base::string16& title) {
892  if (!db_)
893    return;
894
895  URLRow url_info(url);
896  URLID url_id = db_->GetRowForURL(url, &url_info);
897  if (url_id) {
898    // URL is already known, nothing to do.
899    return;
900  }
901
902  if (!title.empty()) {
903    url_info.set_title(title);
904  } else {
905    url_info.set_title(base::UTF8ToUTF16(url.spec()));
906  }
907
908  url_info.set_last_visit(Time::Now());
909  // Mark the page hidden. If the user types it in, it'll unhide.
910  url_info.set_hidden(true);
911
912  db_->AddURL(url_info);
913}
914
915void HistoryBackend::IterateURLs(
916    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
917    iterator) {
918  if (db_) {
919    HistoryDatabase::URLEnumerator e;
920    if (db_->InitURLEnumeratorForEverything(&e)) {
921      URLRow info;
922      while (e.GetNextURL(&info)) {
923        iterator->OnURL(info.url());
924      }
925      iterator->OnComplete(true);  // Success.
926      return;
927    }
928  }
929  iterator->OnComplete(false);  // Failure.
930}
931
932bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
933  if (db_)
934    return db_->GetAllTypedUrls(urls);
935  return false;
936}
937
938bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
939  if (db_)
940    return db_->GetVisitsForURL(id, visits);
941  return false;
942}
943
944bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
945                                               int max_visits,
946                                               VisitVector* visits) {
947  if (db_)
948    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
949  return false;
950}
951
952bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
953  if (db_)
954    return db_->UpdateURLRow(id, url);
955  return false;
956}
957
958bool HistoryBackend::AddVisits(const GURL& url,
959                               const std::vector<VisitInfo>& visits,
960                               VisitSource visit_source) {
961  if (db_) {
962    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
963         visit != visits.end(); ++visit) {
964      if (!AddPageVisit(
965              url, visit->first, 0, visit->second, visit_source).first) {
966        return false;
967      }
968    }
969    ScheduleCommit();
970    return true;
971  }
972  return false;
973}
974
975bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
976  if (!db_)
977    return false;
978
979  expirer_.ExpireVisits(visits);
980  ScheduleCommit();
981  return true;
982}
983
984bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
985                                     VisitSourceMap* sources) {
986  if (!db_)
987    return false;
988
989  db_->GetVisitsSource(visits, sources);
990  return true;
991}
992
993bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
994  if (db_)
995    return db_->GetRowForURL(url, url_row) != 0;
996  return false;
997}
998
999HistoryBackend::QueryURLResult HistoryBackend::QueryURL(const GURL& url,
1000                                                        bool want_visits) {
1001  QueryURLResult result;
1002  result.success = db_ && db_->GetRowForURL(url, &result.row);
1003  // Optionally query the visits.
1004  if (result.success && want_visits)
1005    db_->GetVisitsForURL(result.row.id(), &result.visits);
1006  return result;
1007}
1008
1009TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1010  return typed_url_syncable_service_.get();
1011}
1012
1013// Segment usage ---------------------------------------------------------------
1014
1015void HistoryBackend::DeleteOldSegmentData() {
1016  if (db_)
1017    db_->DeleteSegmentData(Time::Now() -
1018                           TimeDelta::FromDays(kSegmentDataRetention));
1019}
1020
1021void HistoryBackend::QuerySegmentUsage(
1022    scoped_refptr<QuerySegmentUsageRequest> request,
1023    const Time from_time,
1024    int max_result_count) {
1025  if (request->canceled())
1026    return;
1027
1028  if (db_) {
1029    db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
1030
1031    // If this is the first time we query segments, invoke
1032    // DeleteOldSegmentData asynchronously. We do this to cleanup old
1033    // entries.
1034    if (!segment_queried_) {
1035      segment_queried_ = true;
1036      base::MessageLoop::current()->PostTask(
1037          FROM_HERE,
1038          base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
1039    }
1040  }
1041  request->ForwardResult(request->handle(), &request->value.get());
1042}
1043
1044// Keyword visits --------------------------------------------------------------
1045
1046void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
1047                                                 TemplateURLID keyword_id,
1048                                                 const base::string16& term) {
1049  if (!db_)
1050    return;
1051
1052  // Get the ID for this URL.
1053  URLRow row;
1054  if (!db_->GetRowForURL(url, &row)) {
1055    // There is a small possibility the url was deleted before the keyword
1056    // was added. Ignore the request.
1057    return;
1058  }
1059
1060  db_->SetKeywordSearchTermsForURL(row.id(), keyword_id, term);
1061
1062  BroadcastNotifications(
1063      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1064      scoped_ptr<HistoryDetails>(
1065          new KeywordSearchUpdatedDetails(row, keyword_id, term)));
1066  ScheduleCommit();
1067}
1068
1069void HistoryBackend::DeleteAllSearchTermsForKeyword(
1070    TemplateURLID keyword_id) {
1071  if (!db_)
1072    return;
1073
1074  db_->DeleteAllSearchTermsForKeyword(keyword_id);
1075  ScheduleCommit();
1076}
1077
1078void HistoryBackend::GetMostRecentKeywordSearchTerms(
1079    scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
1080    TemplateURLID keyword_id,
1081    const base::string16& prefix,
1082    int max_count) {
1083  if (request->canceled())
1084    return;
1085
1086  if (db_) {
1087    db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
1088                                         &(request->value));
1089  }
1090  request->ForwardResult(request->handle(), &request->value);
1091}
1092
1093void HistoryBackend::DeleteKeywordSearchTermForURL(const GURL& url) {
1094  if (!db_)
1095    return;
1096
1097  URLID url_id = db_->GetRowForURL(url, NULL);
1098  if (!url_id)
1099    return;
1100  db_->DeleteKeywordSearchTermForURL(url_id);
1101
1102  BroadcastNotifications(
1103      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
1104      scoped_ptr<HistoryDetails>(new KeywordSearchDeletedDetails(url_id)));
1105  ScheduleCommit();
1106}
1107
1108void HistoryBackend::DeleteMatchingURLsForKeyword(TemplateURLID keyword_id,
1109                                                  const base::string16& term) {
1110  if (!db_)
1111    return;
1112
1113  std::vector<KeywordSearchTermRow> rows;
1114  if (db_->GetKeywordSearchTermRows(term, &rows)) {
1115    std::vector<GURL> items_to_delete;
1116    URLRow row;
1117    for (std::vector<KeywordSearchTermRow>::iterator it = rows.begin();
1118         it != rows.end(); ++it) {
1119      if ((it->keyword_id == keyword_id) && db_->GetURLRow(it->url_id, &row))
1120        items_to_delete.push_back(row.url());
1121    }
1122    DeleteURLs(items_to_delete);
1123  }
1124}
1125
1126// Downloads -------------------------------------------------------------------
1127
1128uint32 HistoryBackend::GetNextDownloadId() {
1129  return db_ ? db_->GetNextDownloadId() : content::DownloadItem::kInvalidId;
1130}
1131
1132// Get all the download entries from the database.
1133void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1134  if (db_)
1135    db_->QueryDownloads(rows);
1136}
1137
1138// Update a particular download entry.
1139void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1140  if (!db_)
1141    return;
1142  db_->UpdateDownload(data);
1143  ScheduleCommit();
1144}
1145
1146bool HistoryBackend::CreateDownload(const history::DownloadRow& history_info) {
1147  if (!db_)
1148    return false;
1149  bool success = db_->CreateDownload(history_info);
1150  ScheduleCommit();
1151  return success;
1152}
1153
1154void HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1155  if (!db_)
1156    return;
1157  size_t downloads_count_before = db_->CountDownloads();
1158  base::TimeTicks started_removing = base::TimeTicks::Now();
1159  // HistoryBackend uses a long-running Transaction that is committed
1160  // periodically, so this loop doesn't actually hit the disk too hard.
1161  for (std::set<uint32>::const_iterator it = ids.begin();
1162       it != ids.end(); ++it) {
1163    db_->RemoveDownload(*it);
1164  }
1165  ScheduleCommit();
1166  base::TimeTicks finished_removing = base::TimeTicks::Now();
1167  size_t downloads_count_after = db_->CountDownloads();
1168
1169  DCHECK_LE(downloads_count_after, downloads_count_before);
1170  if (downloads_count_after > downloads_count_before)
1171    return;
1172  size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
1173  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
1174                        num_downloads_deleted);
1175  base::TimeDelta micros = (1000 * (finished_removing - started_removing));
1176  UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
1177  if (num_downloads_deleted > 0) {
1178    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
1179                        (1000 * micros) / num_downloads_deleted);
1180  }
1181  DCHECK_GE(ids.size(), num_downloads_deleted);
1182  if (ids.size() < num_downloads_deleted)
1183    return;
1184  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
1185                        ids.size() - num_downloads_deleted);
1186}
1187
1188void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
1189                                  const base::string16& text_query,
1190                                  const QueryOptions& options) {
1191  if (request->canceled())
1192    return;
1193
1194  TimeTicks beginning_time = TimeTicks::Now();
1195
1196  if (db_) {
1197    if (text_query.empty()) {
1198      // Basic history query for the main database.
1199      QueryHistoryBasic(options, &request->value);
1200    } else {
1201      // Text history query.
1202      QueryHistoryText(text_query, options, &request->value);
1203    }
1204  }
1205
1206  request->ForwardResult(request->handle(), &request->value);
1207
1208  UMA_HISTOGRAM_TIMES("History.QueryHistory",
1209                      TimeTicks::Now() - beginning_time);
1210}
1211
1212// Basic time-based querying of history.
1213void HistoryBackend::QueryHistoryBasic(const QueryOptions& options,
1214                                       QueryResults* result) {
1215  // First get all visits.
1216  VisitVector visits;
1217  bool has_more_results = db_->GetVisibleVisitsInRange(options, &visits);
1218  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
1219
1220  // Now add them and the URL rows to the results.
1221  URLResult url_result;
1222  for (size_t i = 0; i < visits.size(); i++) {
1223    const VisitRow visit = visits[i];
1224
1225    // Add a result row for this visit, get the URL info from the DB.
1226    if (!db_->GetURLRow(visit.url_id, &url_result)) {
1227      VLOG(0) << "Failed to get id " << visit.url_id
1228              << " from history.urls.";
1229      continue;  // DB out of sync and URL doesn't exist, try to recover.
1230    }
1231
1232    if (!url_result.url().is_valid()) {
1233      VLOG(0) << "Got invalid URL from history.urls with id "
1234              << visit.url_id << ":  "
1235              << url_result.url().possibly_invalid_spec();
1236      continue;  // Don't report invalid URLs in case of corruption.
1237    }
1238
1239    url_result.set_visit_time(visit.visit_time);
1240
1241    // Set whether the visit was blocked for a managed user by looking at the
1242    // transition type.
1243    url_result.set_blocked_visit(
1244        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1245
1246    // We don't set any of the query-specific parts of the URLResult, since
1247    // snippets and stuff don't apply to basic querying.
1248    result->AppendURLBySwapping(&url_result);
1249  }
1250
1251  if (!has_more_results && options.begin_time <= first_recorded_time_)
1252    result->set_reached_beginning(true);
1253}
1254
1255// Text-based querying of history.
1256void HistoryBackend::QueryHistoryText(const base::string16& text_query,
1257                                      const QueryOptions& options,
1258                                      QueryResults* result) {
1259  URLRows text_matches;
1260  db_->GetTextMatches(text_query, &text_matches);
1261
1262  std::vector<URLResult> matching_visits;
1263  VisitVector visits;    // Declare outside loop to prevent re-construction.
1264  for (size_t i = 0; i < text_matches.size(); i++) {
1265    const URLRow& text_match = text_matches[i];
1266    // Get all visits for given URL match.
1267    db_->GetVisibleVisitsForURL(text_match.id(), options, &visits);
1268    for (size_t j = 0; j < visits.size(); j++) {
1269      URLResult url_result(text_match);
1270      url_result.set_visit_time(visits[j].visit_time);
1271      matching_visits.push_back(url_result);
1272    }
1273  }
1274
1275  std::sort(matching_visits.begin(), matching_visits.end(),
1276            URLResult::CompareVisitTime);
1277
1278  size_t max_results = options.max_count == 0 ?
1279      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1280  for (std::vector<URLResult>::iterator it = matching_visits.begin();
1281       it != matching_visits.end() && result->size() < max_results; ++it) {
1282    result->AppendURLBySwapping(&(*it));
1283  }
1284
1285  if (matching_visits.size() == result->size() &&
1286      options.begin_time <= first_recorded_time_)
1287    result->set_reached_beginning(true);
1288}
1289
1290// Frontend to GetMostRecentRedirectsFrom from the history thread.
1291void HistoryBackend::QueryRedirectsFrom(
1292    scoped_refptr<QueryRedirectsRequest> request,
1293    const GURL& url) {
1294  if (request->canceled())
1295    return;
1296  bool success = GetMostRecentRedirectsFrom(url, &request->value);
1297  request->ForwardResult(request->handle(), url, success, &request->value);
1298}
1299
1300void HistoryBackend::QueryRedirectsTo(
1301    scoped_refptr<QueryRedirectsRequest> request,
1302    const GURL& url) {
1303  if (request->canceled())
1304    return;
1305  bool success = GetMostRecentRedirectsTo(url, &request->value);
1306  request->ForwardResult(request->handle(), url, success, &request->value);
1307}
1308
1309void HistoryBackend::GetVisibleVisitCountToHost(
1310    scoped_refptr<GetVisibleVisitCountToHostRequest> request,
1311    const GURL& url) {
1312  if (request->canceled())
1313    return;
1314  int count = 0;
1315  Time first_visit;
1316  const bool success = db_.get() &&
1317      db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
1318  request->ForwardResult(request->handle(), success, count, first_visit);
1319}
1320
1321void HistoryBackend::QueryTopURLsAndRedirects(
1322    scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
1323    int result_count) {
1324  if (request->canceled())
1325    return;
1326
1327  if (!db_) {
1328    request->ForwardResult(request->handle(), false, NULL, NULL);
1329    return;
1330  }
1331
1332  std::vector<GURL>* top_urls = &request->value.a;
1333  history::RedirectMap* redirects = &request->value.b;
1334
1335  ScopedVector<PageUsageData> data;
1336  db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
1337      result_count, &data.get());
1338
1339  for (size_t i = 0; i < data.size(); ++i) {
1340    top_urls->push_back(data[i]->GetURL());
1341    RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
1342    GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
1343    (*redirects)[top_urls->back()] = list;
1344  }
1345
1346  request->ForwardResult(request->handle(), true, top_urls, redirects);
1347}
1348
1349// Will replace QueryTopURLsAndRedirectsRequest.
1350void HistoryBackend::QueryMostVisitedURLs(
1351    scoped_refptr<QueryMostVisitedURLsRequest> request,
1352    int result_count,
1353    int days_back) {
1354  if (request->canceled())
1355    return;
1356
1357  if (!db_) {
1358    // No History Database - return an empty list.
1359    request->ForwardResult(request->handle(), MostVisitedURLList());
1360    return;
1361  }
1362
1363  MostVisitedURLList* result = &request->value;
1364  QueryMostVisitedURLsImpl(result_count, days_back, result);
1365  request->ForwardResult(request->handle(), *result);
1366}
1367
1368void HistoryBackend::QueryFilteredURLs(
1369      scoped_refptr<QueryFilteredURLsRequest> request,
1370      int result_count,
1371      const history::VisitFilter& filter,
1372      bool extended_info)  {
1373  if (request->canceled())
1374    return;
1375
1376  base::Time request_start = base::Time::Now();
1377
1378  if (!db_) {
1379    // No History Database - return an empty list.
1380    request->ForwardResult(request->handle(), FilteredURLList());
1381    return;
1382  }
1383
1384  VisitVector visits;
1385  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
1386
1387  std::map<URLID, double> score_map;
1388  for (size_t i = 0; i < visits.size(); ++i) {
1389    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
1390  }
1391
1392  // TODO(georgey): experiment with visit_segment database granularity (it is
1393  // currently 24 hours) to use it directly instead of using visits database,
1394  // which is considerably slower.
1395  ScopedVector<PageUsageData> data;
1396  data.reserve(score_map.size());
1397  for (std::map<URLID, double>::iterator it = score_map.begin();
1398       it != score_map.end(); ++it) {
1399    PageUsageData* pud = new PageUsageData(it->first);
1400    pud->SetScore(it->second);
1401    data.push_back(pud);
1402  }
1403
1404  // Limit to the top |result_count| results.
1405  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
1406  if (result_count && implicit_cast<int>(data.size()) > result_count)
1407    data.resize(result_count);
1408
1409  for (size_t i = 0; i < data.size(); ++i) {
1410    URLRow info;
1411    if (db_->GetURLRow(data[i]->GetID(), &info)) {
1412      data[i]->SetURL(info.url());
1413      data[i]->SetTitle(info.title());
1414    }
1415  }
1416
1417  FilteredURLList& result = request->value;
1418  for (size_t i = 0; i < data.size(); ++i) {
1419    PageUsageData* current_data = data[i];
1420    FilteredURL url(*current_data);
1421
1422    if (extended_info) {
1423      VisitVector visits;
1424      db_->GetVisitsForURL(current_data->GetID(), &visits);
1425      if (visits.size() > 0) {
1426        url.extended_info.total_visits = visits.size();
1427        for (size_t i = 0; i < visits.size(); ++i) {
1428          url.extended_info.duration_opened +=
1429              visits[i].visit_duration.InSeconds();
1430          if (visits[i].visit_time > url.extended_info.last_visit_time) {
1431            url.extended_info.last_visit_time = visits[i].visit_time;
1432          }
1433        }
1434        // TODO(macourteau): implement the url.extended_info.visits stat.
1435      }
1436    }
1437    result.push_back(url);
1438  }
1439
1440  int delta_time = std::max(1, std::min(999,
1441      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
1442  STATIC_HISTOGRAM_POINTER_BLOCK(
1443      "NewTabPage.SuggestedSitesLoadTime",
1444      Add(delta_time),
1445      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
1446          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
1447
1448  request->ForwardResult(request->handle(), result);
1449}
1450
1451void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
1452                                              int days_back,
1453                                              MostVisitedURLList* result) {
1454  if (!db_)
1455    return;
1456
1457  ScopedVector<PageUsageData> data;
1458  db_->QuerySegmentUsage(base::Time::Now() -
1459                         base::TimeDelta::FromDays(days_back),
1460                         result_count, &data.get());
1461
1462  for (size_t i = 0; i < data.size(); ++i) {
1463    PageUsageData* current_data = data[i];
1464    RedirectList redirects;
1465    GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
1466    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
1467    result->push_back(url);
1468  }
1469}
1470
1471void HistoryBackend::GetRedirectsFromSpecificVisit(
1472    VisitID cur_visit, history::RedirectList* redirects) {
1473  // Follow any redirects from the given visit and add them to the list.
1474  // It *should* be impossible to get a circular chain here, but we check
1475  // just in case to avoid infinite loops.
1476  GURL cur_url;
1477  std::set<VisitID> visit_set;
1478  visit_set.insert(cur_visit);
1479  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
1480    if (visit_set.find(cur_visit) != visit_set.end()) {
1481      NOTREACHED() << "Loop in visit chain, giving up";
1482      return;
1483    }
1484    visit_set.insert(cur_visit);
1485    redirects->push_back(cur_url);
1486  }
1487}
1488
1489void HistoryBackend::GetRedirectsToSpecificVisit(
1490    VisitID cur_visit,
1491    history::RedirectList* redirects) {
1492  // Follow redirects going to cur_visit. These are added to |redirects| in
1493  // the order they are found. If a redirect chain looks like A -> B -> C and
1494  // |cur_visit| = C, redirects will be {B, A} in that order.
1495  if (!db_)
1496    return;
1497
1498  GURL cur_url;
1499  std::set<VisitID> visit_set;
1500  visit_set.insert(cur_visit);
1501  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
1502    if (visit_set.find(cur_visit) != visit_set.end()) {
1503      NOTREACHED() << "Loop in visit chain, giving up";
1504      return;
1505    }
1506    visit_set.insert(cur_visit);
1507    redirects->push_back(cur_url);
1508  }
1509}
1510
1511bool HistoryBackend::GetMostRecentRedirectsFrom(
1512    const GURL& from_url,
1513    history::RedirectList* redirects) {
1514  redirects->clear();
1515  if (!db_)
1516    return false;
1517
1518  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
1519  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
1520  if (!cur_visit)
1521    return false;  // No visits for URL.
1522
1523  GetRedirectsFromSpecificVisit(cur_visit, redirects);
1524  return true;
1525}
1526
1527bool HistoryBackend::GetMostRecentRedirectsTo(
1528    const GURL& to_url,
1529    history::RedirectList* redirects) {
1530  redirects->clear();
1531  if (!db_)
1532    return false;
1533
1534  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
1535  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
1536  if (!cur_visit)
1537    return false;  // No visits for URL.
1538
1539  GetRedirectsToSpecificVisit(cur_visit, redirects);
1540  return true;
1541}
1542
1543void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1544                                          HistoryURLProviderParams* params) {
1545  // ExecuteWithDB should handle the NULL database case.
1546  provider->ExecuteWithDB(this, db_.get(), params);
1547}
1548
1549void HistoryBackend::DeleteFTSIndexDatabases() {
1550  // Find files on disk matching the text databases file pattern so we can
1551  // quickly test for and delete them.
1552  base::FilePath::StringType filepattern =
1553      FILE_PATH_LITERAL("History Index *");
1554  base::FileEnumerator enumerator(
1555      history_dir_, false, base::FileEnumerator::FILES, filepattern);
1556  int num_databases_deleted = 0;
1557  base::FilePath current_file;
1558  while (!(current_file = enumerator.Next()).empty()) {
1559    if (sql::Connection::Delete(current_file))
1560      num_databases_deleted++;
1561  }
1562  UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1563                       num_databases_deleted);
1564}
1565
1566void HistoryBackend::GetFavicons(
1567    const std::vector<GURL>& icon_urls,
1568    int icon_types,
1569    const std::vector<int>& desired_sizes,
1570    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1571  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types, desired_sizes,
1572                                    bitmap_results);
1573}
1574
1575void HistoryBackend::GetLargestFaviconForURL(
1576    const GURL& page_url,
1577    const std::vector<int>& icon_types,
1578    int minimum_size_in_pixels,
1579    favicon_base::FaviconRawBitmapResult* favicon_bitmap_result) {
1580  DCHECK(favicon_bitmap_result);
1581
1582  if (!db_ || !thumbnail_db_)
1583    return;
1584
1585  TimeTicks beginning_time = TimeTicks::Now();
1586
1587  std::vector<IconMapping> icon_mappings;
1588  if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
1589      icon_mappings.empty())
1590    return;
1591
1592  int required_icon_types = 0;
1593  for (std::vector<int>::const_iterator i = icon_types.begin();
1594       i != icon_types.end(); ++i) {
1595    required_icon_types |= *i;
1596  }
1597
1598  // Find the largest bitmap for each IconType placing in
1599  // |largest_favicon_bitmaps|.
1600  std::map<favicon_base::IconType, FaviconBitmap> largest_favicon_bitmaps;
1601  for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
1602       i != icon_mappings.end(); ++i) {
1603    if (!(i->icon_type & required_icon_types))
1604      continue;
1605    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
1606    thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
1607    FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
1608    for (std::vector<FaviconBitmapIDSize>::const_iterator j =
1609             bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
1610      if (largest.bitmap_id == 0 ||
1611          (largest.pixel_size.width() < j->pixel_size.width() &&
1612           largest.pixel_size.height() < j->pixel_size.height())) {
1613        largest.icon_id = i->icon_id;
1614        largest.bitmap_id = j->bitmap_id;
1615        largest.pixel_size = j->pixel_size;
1616      }
1617    }
1618  }
1619  if (largest_favicon_bitmaps.empty())
1620    return;
1621
1622  // Find an icon which is larger than minimum_size_in_pixels in the order of
1623  // icon_types.
1624  FaviconBitmap largest_icon;
1625  for (std::vector<int>::const_iterator t = icon_types.begin();
1626       t != icon_types.end(); ++t) {
1627    for (std::map<favicon_base::IconType, FaviconBitmap>::const_iterator f =
1628             largest_favicon_bitmaps.begin();
1629         f != largest_favicon_bitmaps.end();
1630         ++f) {
1631      if (f->first & *t &&
1632          (largest_icon.bitmap_id == 0 ||
1633           (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
1634            largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
1635        largest_icon = f->second;
1636      }
1637    }
1638    if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
1639        largest_icon.pixel_size.height() > minimum_size_in_pixels)
1640      break;
1641  }
1642
1643  GURL icon_url;
1644  favicon_base::IconType icon_type;
1645  if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
1646                                       &icon_type)) {
1647    return;
1648  }
1649
1650  base::Time last_updated;
1651  favicon_base::FaviconRawBitmapResult bitmap_result;
1652  bitmap_result.icon_url = icon_url;
1653  bitmap_result.icon_type = icon_type;
1654  if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
1655                                       &last_updated,
1656                                       &bitmap_result.bitmap_data,
1657                                       &bitmap_result.pixel_size)) {
1658    return;
1659  }
1660
1661  bitmap_result.expired = (Time::Now() - last_updated) >
1662      TimeDelta::FromDays(kFaviconRefetchDays);
1663  if (bitmap_result.is_valid())
1664    *favicon_bitmap_result = bitmap_result;
1665
1666  HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
1667                  TimeTicks::Now() - beginning_time);
1668}
1669
1670void HistoryBackend::GetFaviconsForURL(
1671    const GURL& page_url,
1672    int icon_types,
1673    const std::vector<int>& desired_sizes,
1674    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1675  DCHECK(bitmap_results);
1676  GetFaviconsFromDB(page_url, icon_types, desired_sizes, bitmap_results);
1677}
1678
1679void HistoryBackend::GetFaviconForID(
1680    favicon_base::FaviconID favicon_id,
1681    int desired_size,
1682    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1683  std::vector<favicon_base::FaviconID> favicon_ids;
1684  favicon_ids.push_back(favicon_id);
1685  std::vector<int> desired_sizes;
1686  desired_sizes.push_back(desired_size);
1687
1688  // Get results from DB.
1689  GetFaviconBitmapResultsForBestMatch(favicon_ids,
1690                                      desired_sizes,
1691                                      bitmap_results);
1692}
1693
1694void HistoryBackend::UpdateFaviconMappingsAndFetch(
1695    const GURL& page_url,
1696    const std::vector<GURL>& icon_urls,
1697    int icon_types,
1698    const std::vector<int>& desired_sizes,
1699    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
1700  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
1701                                    desired_sizes, bitmap_results);
1702}
1703
1704void HistoryBackend::MergeFavicon(
1705    const GURL& page_url,
1706    const GURL& icon_url,
1707    favicon_base::IconType icon_type,
1708    scoped_refptr<base::RefCountedMemory> bitmap_data,
1709    const gfx::Size& pixel_size) {
1710  if (!thumbnail_db_ || !db_)
1711    return;
1712
1713  favicon_base::FaviconID favicon_id =
1714      thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
1715
1716  if (!favicon_id) {
1717    // There is no favicon at |icon_url|, create it.
1718    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
1719  }
1720
1721  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
1722  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
1723
1724  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
1725  // replace it.
1726  bool bitmap_identical = false;
1727  bool replaced_bitmap = false;
1728  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
1729    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
1730      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
1731        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
1732            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
1733        bitmap_identical = true;
1734      } else {
1735        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
1736            bitmap_data, base::Time::Now());
1737        replaced_bitmap = true;
1738      }
1739      break;
1740    }
1741  }
1742
1743  // Create a vector of the pixel sizes of the favicon bitmaps currently at
1744  // |icon_url|.
1745  std::vector<gfx::Size> favicon_sizes;
1746  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
1747    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
1748
1749  if (!replaced_bitmap && !bitmap_identical) {
1750    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
1751    // bitmaps are not consistent with the merged in data.
1752    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
1753
1754    // Delete an arbitrary favicon bitmap to avoid going over the limit of
1755    // |kMaxFaviconBitmapsPerIconURL|.
1756    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
1757      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
1758      favicon_sizes.erase(favicon_sizes.begin());
1759    }
1760    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
1761                                    pixel_size);
1762    favicon_sizes.push_back(pixel_size);
1763  }
1764
1765  // A site may have changed the favicons that it uses for |page_url|.
1766  // Example Scenario:
1767  //   page_url = news.google.com
1768  //   Initial State: www.google.com/favicon.ico 16x16, 32x32
1769  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
1770  //                ..., 16x16)
1771  //
1772  // Difficulties:
1773  // 1. Sync requires that a call to GetFaviconsForURL() returns the
1774  //    |bitmap_data| passed into MergeFavicon().
1775  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
1776  //      stay mapped to news.google.com because it would be unclear which 16x16
1777  //      bitmap should be returned via GetFaviconsForURL().
1778  //
1779  // 2. www.google.com/favicon.ico may be mapped to more than just
1780  //    news.google.com (eg www.google.com).
1781  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
1782  //
1783  // To resolve these problems, we copy all of the favicon bitmaps previously
1784  // mapped to news.google.com (|page_url|) and add them to the favicon at
1785  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
1786  // |icon_url| are set to default to indicate that |icon_url| has incomplete
1787  // / incorrect data.
1788  // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
1789  //              news.google.com
1790  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
1791  //               modified.
1792
1793  std::vector<IconMapping> icon_mappings;
1794  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
1795
1796  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
1797  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
1798  for (size_t i = 0; i < icon_mappings.size(); ++i) {
1799    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
1800      break;
1801
1802    if (icon_mappings[i].icon_url == icon_url)
1803      continue;
1804
1805    std::vector<FaviconBitmap> bitmaps_to_copy;
1806    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
1807                                     &bitmaps_to_copy);
1808    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
1809      // Do not add a favicon bitmap at a pixel size for which there is already
1810      // a favicon bitmap mapped to |icon_url|. The one there is more correct
1811      // and having multiple equally sized favicon bitmaps for |page_url| is
1812      // ambiguous in terms of GetFaviconsForURL().
1813      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
1814          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
1815      if (it != favicon_sizes.end())
1816        continue;
1817
1818      // Add the favicon bitmap as expired as it is not consistent with the
1819      // merged in data.
1820      thumbnail_db_->AddFaviconBitmap(favicon_id,
1821          bitmaps_to_copy[j].bitmap_data, base::Time(),
1822          bitmaps_to_copy[j].pixel_size);
1823      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
1824
1825      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
1826        break;
1827    }
1828  }
1829
1830  // Update the favicon mappings such that only |icon_url| is mapped to
1831  // |page_url|.
1832  bool mapping_changed = false;
1833  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
1834    std::vector<favicon_base::FaviconID> favicon_ids;
1835    favicon_ids.push_back(favicon_id);
1836    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
1837    mapping_changed = true;
1838  }
1839
1840  if (mapping_changed || !bitmap_identical)
1841    SendFaviconChangedNotificationForPageAndRedirects(page_url);
1842  ScheduleCommit();
1843}
1844
1845void HistoryBackend::SetFavicons(
1846    const GURL& page_url,
1847    favicon_base::IconType icon_type,
1848    const std::vector<favicon_base::FaviconRawBitmapData>&
1849        favicon_bitmap_data) {
1850  if (!thumbnail_db_ || !db_)
1851    return;
1852
1853  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
1854
1855  // Build map of FaviconRawBitmapData for each icon url.
1856  typedef std::map<GURL, std::vector<favicon_base::FaviconRawBitmapData> >
1857      BitmapDataByIconURL;
1858  BitmapDataByIconURL grouped_by_icon_url;
1859  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
1860    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
1861    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
1862  }
1863
1864  // Track whether the method modifies or creates any favicon bitmaps, favicons
1865  // or icon mappings.
1866  bool data_modified = false;
1867
1868  std::vector<favicon_base::FaviconID> icon_ids;
1869  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
1870       it != grouped_by_icon_url.end(); ++it) {
1871    const GURL& icon_url = it->first;
1872    favicon_base::FaviconID icon_id =
1873        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
1874
1875    if (!icon_id) {
1876      // TODO(pkotwicz): Remove the favicon sizes attribute from
1877      // ThumbnailDatabase::AddFavicon().
1878      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
1879      data_modified = true;
1880    }
1881    icon_ids.push_back(icon_id);
1882
1883    if (!data_modified)
1884      SetFaviconBitmaps(icon_id, it->second, &data_modified);
1885    else
1886      SetFaviconBitmaps(icon_id, it->second, NULL);
1887  }
1888
1889  data_modified |=
1890    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
1891
1892  if (data_modified) {
1893    // Send notification to the UI as an icon mapping, favicon, or favicon
1894    // bitmap was changed by this function.
1895    SendFaviconChangedNotificationForPageAndRedirects(page_url);
1896  }
1897  ScheduleCommit();
1898}
1899
1900void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
1901  std::vector<IconMapping> icon_mappings;
1902
1903  if (!thumbnail_db_ ||
1904      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
1905                                                &icon_mappings))
1906    return;
1907
1908  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
1909       m != icon_mappings.end(); ++m) {
1910    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
1911  }
1912  ScheduleCommit();
1913}
1914
1915void HistoryBackend::CloneFavicons(const GURL& old_page_url,
1916                                   const GURL& new_page_url) {
1917  if (!thumbnail_db_)
1918    return;
1919
1920  // Prevent cross-domain cloning.
1921  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
1922    return;
1923
1924  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
1925  ScheduleCommit();
1926}
1927
1928void HistoryBackend::SetImportedFavicons(
1929    const std::vector<ImportedFaviconUsage>& favicon_usage) {
1930  if (!db_ || !thumbnail_db_)
1931    return;
1932
1933  Time now = Time::Now();
1934
1935  // Track all URLs that had their favicons set or updated.
1936  std::set<GURL> favicons_changed;
1937
1938  for (size_t i = 0; i < favicon_usage.size(); i++) {
1939    favicon_base::FaviconID favicon_id =
1940        thumbnail_db_->GetFaviconIDForFaviconURL(
1941            favicon_usage[i].favicon_url, favicon_base::FAVICON, NULL);
1942    if (!favicon_id) {
1943      // This favicon doesn't exist yet, so we create it using the given data.
1944      // TODO(pkotwicz): Pass in real pixel size.
1945      favicon_id = thumbnail_db_->AddFavicon(
1946          favicon_usage[i].favicon_url,
1947          favicon_base::FAVICON,
1948          new base::RefCountedBytes(favicon_usage[i].png_data),
1949          now,
1950          gfx::Size());
1951    }
1952
1953    // Save the mapping from all the URLs to the favicon.
1954    HistoryClient* history_client = GetHistoryClient();
1955    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
1956         url != favicon_usage[i].urls.end(); ++url) {
1957      URLRow url_row;
1958      if (!db_->GetRowForURL(*url, &url_row)) {
1959        // If the URL is present as a bookmark, add the url in history to
1960        // save the favicon mapping. This will match with what history db does
1961        // for regular bookmarked URLs with favicons - when history db is
1962        // cleaned, we keep an entry in the db with 0 visits as long as that
1963        // url is bookmarked.
1964        if (history_client && history_client->IsBookmarked(*url)) {
1965          URLRow url_info(*url);
1966          url_info.set_visit_count(0);
1967          url_info.set_typed_count(0);
1968          url_info.set_last_visit(base::Time());
1969          url_info.set_hidden(false);
1970          db_->AddURL(url_info);
1971          thumbnail_db_->AddIconMapping(*url, favicon_id);
1972          favicons_changed.insert(*url);
1973        }
1974      } else {
1975        if (!thumbnail_db_->GetIconMappingsForPageURL(
1976                *url, favicon_base::FAVICON, NULL)) {
1977          // URL is present in history, update the favicon *only* if it is not
1978          // set already.
1979          thumbnail_db_->AddIconMapping(*url, favicon_id);
1980          favicons_changed.insert(*url);
1981        }
1982      }
1983    }
1984  }
1985
1986  if (!favicons_changed.empty()) {
1987    // Send the notification about the changed favicon URLs.
1988    scoped_ptr<FaviconChangedDetails> changed_details(
1989        new FaviconChangedDetails);
1990    changed_details->urls.swap(favicons_changed);
1991    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
1992                           changed_details.PassAs<HistoryDetails>());
1993  }
1994}
1995
1996void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
1997    const GURL* page_url,
1998    const std::vector<GURL>& icon_urls,
1999    int icon_types,
2000    const std::vector<int>& desired_sizes,
2001    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
2002  // If |page_url| is specified, |icon_types| must be either a single icon
2003  // type or icon types which are equivalent.
2004  DCHECK(!page_url || icon_types == favicon_base::FAVICON ||
2005         icon_types == favicon_base::TOUCH_ICON ||
2006         icon_types == favicon_base::TOUCH_PRECOMPOSED_ICON ||
2007         icon_types ==
2008             (favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON));
2009  bitmap_results->clear();
2010
2011  if (!thumbnail_db_) {
2012    return;
2013  }
2014
2015  std::vector<favicon_base::FaviconID> favicon_ids;
2016
2017  // The icon type for which the mappings will the updated and data will be
2018  // returned.
2019  favicon_base::IconType selected_icon_type = favicon_base::INVALID_ICON;
2020
2021  for (size_t i = 0; i < icon_urls.size(); ++i) {
2022    const GURL& icon_url = icon_urls[i];
2023    favicon_base::IconType icon_type_out;
2024    const favicon_base::FaviconID favicon_id =
2025        thumbnail_db_->GetFaviconIDForFaviconURL(
2026            icon_url, icon_types, &icon_type_out);
2027
2028    if (favicon_id) {
2029      // Return and update icon mappings only for the largest icon type. As
2030      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
2031      // if an |icon_url| with a larger icon type is found.
2032      if (icon_type_out > selected_icon_type) {
2033        selected_icon_type = icon_type_out;
2034        favicon_ids.clear();
2035      }
2036      if (icon_type_out == selected_icon_type)
2037        favicon_ids.push_back(favicon_id);
2038    }
2039  }
2040
2041  if (page_url && !favicon_ids.empty()) {
2042    bool mappings_updated =
2043        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
2044                                              favicon_ids);
2045    if (mappings_updated) {
2046      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
2047      ScheduleCommit();
2048    }
2049  }
2050
2051  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_sizes,
2052      bitmap_results);
2053}
2054
2055void HistoryBackend::SetFaviconBitmaps(
2056    favicon_base::FaviconID icon_id,
2057    const std::vector<favicon_base::FaviconRawBitmapData>& favicon_bitmap_data,
2058    bool* favicon_bitmaps_changed) {
2059  if (favicon_bitmaps_changed)
2060    *favicon_bitmaps_changed = false;
2061
2062  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
2063  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
2064
2065  std::vector<favicon_base::FaviconRawBitmapData> to_add = favicon_bitmap_data;
2066
2067  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
2068    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
2069    std::vector<favicon_base::FaviconRawBitmapData>::iterator match_it =
2070        to_add.end();
2071    for (std::vector<favicon_base::FaviconRawBitmapData>::iterator it =
2072             to_add.begin();
2073         it != to_add.end();
2074         ++it) {
2075      if (it->pixel_size == pixel_size) {
2076        match_it = it;
2077        break;
2078      }
2079    }
2080
2081    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
2082    if (match_it == to_add.end()) {
2083      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
2084
2085      if (favicon_bitmaps_changed)
2086        *favicon_bitmaps_changed = true;
2087    } else {
2088      if (favicon_bitmaps_changed &&
2089          !*favicon_bitmaps_changed &&
2090          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
2091        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
2092            bitmap_id, base::Time::Now());
2093      } else {
2094        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
2095            base::Time::Now());
2096
2097        if (favicon_bitmaps_changed)
2098          *favicon_bitmaps_changed = true;
2099      }
2100      to_add.erase(match_it);
2101    }
2102  }
2103
2104  for (size_t i = 0; i < to_add.size(); ++i) {
2105    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
2106        base::Time::Now(), to_add[i].pixel_size);
2107
2108    if (favicon_bitmaps_changed)
2109      *favicon_bitmaps_changed = true;
2110  }
2111}
2112
2113bool HistoryBackend::ValidateSetFaviconsParams(const std::vector<
2114    favicon_base::FaviconRawBitmapData>& favicon_bitmap_data) const {
2115  typedef std::map<GURL, size_t> BitmapsPerIconURL;
2116  BitmapsPerIconURL num_bitmaps_per_icon_url;
2117  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2118    if (!favicon_bitmap_data[i].bitmap_data.get())
2119      return false;
2120
2121    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
2122    if (!num_bitmaps_per_icon_url.count(icon_url))
2123      num_bitmaps_per_icon_url[icon_url] = 1u;
2124    else
2125      ++num_bitmaps_per_icon_url[icon_url];
2126  }
2127
2128  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
2129    return false;
2130
2131  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
2132       it != num_bitmaps_per_icon_url.end(); ++it) {
2133    if (it->second > kMaxFaviconBitmapsPerIconURL)
2134      return false;
2135  }
2136  return true;
2137}
2138
2139bool HistoryBackend::IsFaviconBitmapDataEqual(
2140    FaviconBitmapID bitmap_id,
2141    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2142  if (!new_bitmap_data.get())
2143    return false;
2144
2145  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
2146  thumbnail_db_->GetFaviconBitmap(bitmap_id,
2147                                  NULL,
2148                                  &original_bitmap_data,
2149                                  NULL);
2150  return new_bitmap_data->Equals(original_bitmap_data);
2151}
2152
2153bool HistoryBackend::GetFaviconsFromDB(
2154    const GURL& page_url,
2155    int icon_types,
2156    const std::vector<int>& desired_sizes,
2157    std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
2158  DCHECK(favicon_bitmap_results);
2159  favicon_bitmap_results->clear();
2160
2161  if (!db_ || !thumbnail_db_)
2162    return false;
2163
2164  // Time the query.
2165  TimeTicks beginning_time = TimeTicks::Now();
2166
2167  // Get FaviconIDs for |page_url| and one of |icon_types|.
2168  std::vector<IconMapping> icon_mappings;
2169  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
2170                                           &icon_mappings);
2171  std::vector<favicon_base::FaviconID> favicon_ids;
2172  for (size_t i = 0; i < icon_mappings.size(); ++i)
2173    favicon_ids.push_back(icon_mappings[i].icon_id);
2174
2175  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
2176  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
2177      desired_sizes, favicon_bitmap_results);
2178  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
2179                      TimeTicks::Now() - beginning_time);
2180  return success && !favicon_bitmap_results->empty();
2181}
2182
2183bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
2184    const std::vector<favicon_base::FaviconID>& candidate_favicon_ids,
2185    const std::vector<int>& desired_sizes,
2186    std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
2187  favicon_bitmap_results->clear();
2188
2189  if (candidate_favicon_ids.empty())
2190    return true;
2191
2192  // Find the FaviconID and the FaviconBitmapIDs which best match
2193  // |desired_size_in_dip| and |desired_scale_factors|.
2194  // TODO(pkotwicz): Select bitmap results from multiple favicons once
2195  // content::FaviconStatus supports multiple icon URLs.
2196  favicon_base::FaviconID best_favicon_id = 0;
2197  std::vector<FaviconBitmapID> best_bitmap_ids;
2198  float highest_score = kSelectFaviconFramesInvalidScore;
2199  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
2200    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
2201    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
2202                                           &bitmap_id_sizes);
2203
2204    // Build vector of gfx::Size from |bitmap_id_sizes|.
2205    std::vector<gfx::Size> sizes;
2206    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
2207      sizes.push_back(bitmap_id_sizes[j].pixel_size);
2208
2209    std::vector<size_t> candidate_bitmap_indices;
2210    float score = 0;
2211    SelectFaviconFrameIndices(sizes,
2212                              desired_sizes,
2213                              &candidate_bitmap_indices,
2214                              &score);
2215    if (score > highest_score) {
2216      highest_score = score;
2217      best_favicon_id = candidate_favicon_ids[i],
2218      best_bitmap_ids.clear();
2219      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
2220        size_t candidate_index = candidate_bitmap_indices[j];
2221        best_bitmap_ids.push_back(
2222            bitmap_id_sizes[candidate_index].bitmap_id);
2223      }
2224    }
2225  }
2226
2227  // Construct FaviconRawBitmapResults from |best_favicon_id| and
2228  // |best_bitmap_ids|.
2229  GURL icon_url;
2230  favicon_base::IconType icon_type;
2231  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2232                                       &icon_type)) {
2233    return false;
2234  }
2235
2236  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
2237    base::Time last_updated;
2238    favicon_base::FaviconRawBitmapResult bitmap_result;
2239    bitmap_result.icon_url = icon_url;
2240    bitmap_result.icon_type = icon_type;
2241    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
2242                                         &last_updated,
2243                                         &bitmap_result.bitmap_data,
2244                                         &bitmap_result.pixel_size)) {
2245      return false;
2246    }
2247
2248    bitmap_result.expired = (Time::Now() - last_updated) >
2249        TimeDelta::FromDays(kFaviconRefetchDays);
2250    if (bitmap_result.is_valid())
2251      favicon_bitmap_results->push_back(bitmap_result);
2252  }
2253  return true;
2254}
2255
2256bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
2257    const GURL& page_url,
2258    favicon_base::IconType icon_type,
2259    const std::vector<favicon_base::FaviconID>& icon_ids) {
2260  if (!thumbnail_db_)
2261    return false;
2262
2263  // Find all the pages whose favicons we should set, we want to set it for
2264  // all the pages in the redirect chain if it redirected.
2265  history::RedirectList redirects;
2266  GetCachedRecentRedirects(page_url, &redirects);
2267
2268  bool mappings_changed = false;
2269
2270  // Save page <-> favicon associations.
2271  for (history::RedirectList::const_iterator i(redirects.begin());
2272       i != redirects.end(); ++i) {
2273    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
2274  }
2275  return mappings_changed;
2276}
2277
2278bool HistoryBackend::SetFaviconMappingsForPage(
2279    const GURL& page_url,
2280    favicon_base::IconType icon_type,
2281    const std::vector<favicon_base::FaviconID>& icon_ids) {
2282  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
2283  bool mappings_changed = false;
2284
2285  // Two icon types are considered 'equivalent' if one of the icon types is
2286  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
2287  //
2288  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
2289  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
2290  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
2291  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
2292  // Remove any favicons which are orphaned as a result of the removal of the
2293  // icon mappings.
2294
2295  std::vector<favicon_base::FaviconID> unmapped_icon_ids = icon_ids;
2296
2297  std::vector<IconMapping> icon_mappings;
2298  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
2299
2300  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
2301       m != icon_mappings.end(); ++m) {
2302    std::vector<favicon_base::FaviconID>::iterator icon_id_it = std::find(
2303        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
2304
2305    // If the icon mapping already exists, avoid removing it and adding it back.
2306    if (icon_id_it != unmapped_icon_ids.end()) {
2307      unmapped_icon_ids.erase(icon_id_it);
2308      continue;
2309    }
2310
2311    if ((icon_type == favicon_base::TOUCH_ICON &&
2312         m->icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON) ||
2313        (icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON &&
2314         m->icon_type == favicon_base::TOUCH_ICON) ||
2315        (icon_type == m->icon_type)) {
2316      thumbnail_db_->DeleteIconMapping(m->mapping_id);
2317
2318      // Removing the icon mapping may have orphaned the associated favicon so
2319      // we must recheck it. This is not super fast, but this case will get
2320      // triggered rarely, since normally a page will always map to the same
2321      // favicon IDs. It will mostly happen for favicons we import.
2322      if (!thumbnail_db_->HasMappingFor(m->icon_id))
2323        thumbnail_db_->DeleteFavicon(m->icon_id);
2324      mappings_changed = true;
2325    }
2326  }
2327
2328  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
2329    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
2330    mappings_changed = true;
2331  }
2332  return mappings_changed;
2333}
2334
2335void HistoryBackend::GetCachedRecentRedirects(
2336    const GURL& page_url,
2337    history::RedirectList* redirect_list) {
2338  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
2339  if (iter != recent_redirects_.end()) {
2340    *redirect_list = iter->second;
2341
2342    // The redirect chain should have the destination URL as the last item.
2343    DCHECK(!redirect_list->empty());
2344    DCHECK(redirect_list->back() == page_url);
2345  } else {
2346    // No known redirects, construct mock redirect chain containing |page_url|.
2347    redirect_list->push_back(page_url);
2348  }
2349}
2350
2351void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
2352    const GURL& page_url) {
2353  history::RedirectList redirect_list;
2354  GetCachedRecentRedirects(page_url, &redirect_list);
2355
2356  scoped_ptr<FaviconChangedDetails> changed_details(new FaviconChangedDetails);
2357  for (size_t i = 0; i < redirect_list.size(); ++i)
2358    changed_details->urls.insert(redirect_list[i]);
2359
2360  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2361                         changed_details.PassAs<HistoryDetails>());
2362}
2363
2364void HistoryBackend::Commit() {
2365  if (!db_)
2366    return;
2367
2368  // Note that a commit may not actually have been scheduled if a caller
2369  // explicitly calls this instead of using ScheduleCommit. Likewise, we
2370  // may reset the flag written by a pending commit. But this is OK! It
2371  // will merely cause extra commits (which is kind of the idea). We
2372  // could optimize more for this case (we may get two extra commits in
2373  // some cases) but it hasn't been important yet.
2374  CancelScheduledCommit();
2375
2376  db_->CommitTransaction();
2377  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
2378  db_->BeginTransaction();
2379
2380  if (thumbnail_db_) {
2381    thumbnail_db_->CommitTransaction();
2382    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
2383        "Somebody left a transaction open";
2384    thumbnail_db_->BeginTransaction();
2385  }
2386}
2387
2388void HistoryBackend::ScheduleCommit() {
2389  if (scheduled_commit_.get())
2390    return;
2391  scheduled_commit_ = new CommitLaterTask(this);
2392  base::MessageLoop::current()->PostDelayedTask(
2393      FROM_HERE,
2394      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
2395      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
2396}
2397
2398void HistoryBackend::CancelScheduledCommit() {
2399  if (scheduled_commit_.get()) {
2400    scheduled_commit_->Cancel();
2401    scheduled_commit_ = NULL;
2402  }
2403}
2404
2405void HistoryBackend::ProcessDBTaskImpl() {
2406  if (!db_) {
2407    // db went away, release all the refs.
2408    ReleaseDBTasks();
2409    return;
2410  }
2411
2412  // Remove any canceled tasks.
2413  while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
2414    db_task_requests_.front()->Release();
2415    db_task_requests_.pop_front();
2416  }
2417  if (db_task_requests_.empty())
2418    return;
2419
2420  // Run the first task.
2421  HistoryDBTaskRequest* request = db_task_requests_.front();
2422  db_task_requests_.pop_front();
2423  if (request->value->RunOnDBThread(this, db_.get())) {
2424    // The task is done. Notify the callback.
2425    request->ForwardResult();
2426    // We AddRef'd the request before adding, need to release it now.
2427    request->Release();
2428  } else {
2429    // Tasks wants to run some more. Schedule it at the end of current tasks.
2430    db_task_requests_.push_back(request);
2431    // And process it after an invoke later.
2432    base::MessageLoop::current()->PostTask(
2433        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
2434  }
2435}
2436
2437void HistoryBackend::ReleaseDBTasks() {
2438  for (std::list<HistoryDBTaskRequest*>::iterator i =
2439       db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
2440    (*i)->Release();
2441  }
2442  db_task_requests_.clear();
2443}
2444
2445////////////////////////////////////////////////////////////////////////////////
2446//
2447// Generic operations
2448//
2449////////////////////////////////////////////////////////////////////////////////
2450
2451void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
2452  expirer_.DeleteURLs(urls);
2453
2454  db_->GetStartDate(&first_recorded_time_);
2455  // Force a commit, if the user is deleting something for privacy reasons, we
2456  // want to get it on disk ASAP.
2457  Commit();
2458}
2459
2460void HistoryBackend::DeleteURL(const GURL& url) {
2461  expirer_.DeleteURL(url);
2462
2463  db_->GetStartDate(&first_recorded_time_);
2464  // Force a commit, if the user is deleting something for privacy reasons, we
2465  // want to get it on disk ASAP.
2466  Commit();
2467}
2468
2469void HistoryBackend::ExpireHistoryBetween(
2470    const std::set<GURL>& restrict_urls,
2471    Time begin_time,
2472    Time end_time) {
2473  if (!db_)
2474    return;
2475
2476  if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
2477      restrict_urls.empty()) {
2478    // Special case deleting all history so it can be faster and to reduce the
2479    // possibility of an information leak.
2480    DeleteAllHistory();
2481  } else {
2482    // Clearing parts of history, have the expirer do the depend
2483    expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
2484
2485    // Force a commit, if the user is deleting something for privacy reasons,
2486    // we want to get it on disk ASAP.
2487    Commit();
2488  }
2489
2490  if (begin_time <= first_recorded_time_)
2491    db_->GetStartDate(&first_recorded_time_);
2492}
2493
2494void HistoryBackend::ExpireHistoryForTimes(
2495    const std::set<base::Time>& times,
2496    base::Time begin_time, base::Time end_time) {
2497  if (times.empty() || !db_)
2498    return;
2499
2500  DCHECK(*times.begin() >= begin_time)
2501      << "Min time is before begin time: "
2502      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
2503  DCHECK(*times.rbegin() < end_time)
2504      << "Max time is after end time: "
2505      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
2506
2507  history::QueryOptions options;
2508  options.begin_time = begin_time;
2509  options.end_time = end_time;
2510  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
2511  QueryResults results;
2512  QueryHistoryBasic(options, &results);
2513
2514  // 1st pass: find URLs that are visited at one of |times|.
2515  std::set<GURL> urls;
2516  for (size_t i = 0; i < results.size(); ++i) {
2517    if (times.count(results[i].visit_time()) > 0)
2518      urls.insert(results[i].url());
2519  }
2520  if (urls.empty())
2521    return;
2522
2523  // 2nd pass: collect all visit times of those URLs.
2524  std::vector<base::Time> times_to_expire;
2525  for (size_t i = 0; i < results.size(); ++i) {
2526    if (urls.count(results[i].url()))
2527      times_to_expire.push_back(results[i].visit_time());
2528  }
2529
2530  // Put the times in reverse chronological order and remove
2531  // duplicates (for expirer_.ExpireHistoryForTimes()).
2532  std::sort(times_to_expire.begin(), times_to_expire.end(),
2533            std::greater<base::Time>());
2534  times_to_expire.erase(
2535      std::unique(times_to_expire.begin(), times_to_expire.end()),
2536      times_to_expire.end());
2537
2538  // Expires by times and commit.
2539  DCHECK(!times_to_expire.empty());
2540  expirer_.ExpireHistoryForTimes(times_to_expire);
2541  Commit();
2542
2543  DCHECK(times_to_expire.back() >= first_recorded_time_);
2544  // Update |first_recorded_time_| if we expired it.
2545  if (times_to_expire.back() == first_recorded_time_)
2546    db_->GetStartDate(&first_recorded_time_);
2547}
2548
2549void HistoryBackend::ExpireHistory(
2550    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2551  if (db_) {
2552    bool update_first_recorded_time = false;
2553
2554    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
2555         expire_list.begin(); it != expire_list.end(); ++it) {
2556      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
2557
2558      if (it->begin_time < first_recorded_time_)
2559        update_first_recorded_time = true;
2560    }
2561    Commit();
2562
2563    // Update |first_recorded_time_| if any deletion might have affected it.
2564    if (update_first_recorded_time)
2565      db_->GetStartDate(&first_recorded_time_);
2566  }
2567}
2568
2569void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2570  if (!db_)
2571    return;
2572
2573  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
2574    URLRow url_row;
2575    if (!db_->GetRowForURL(*i, &url_row))
2576      continue;  // The URL isn't in the db; nothing to do.
2577
2578    VisitVector visits;
2579    db_->GetVisitsForURL(url_row.id(), &visits);
2580
2581    if (visits.empty())
2582      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
2583  }
2584}
2585
2586void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
2587  if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
2588    scheduled_kill_db_ = true;
2589    // Don't just do the close/delete here, as we are being called by |db| and
2590    // that seems dangerous.
2591    // TODO(shess): Consider changing KillHistoryDatabase() to use
2592    // RazeAndClose().  Then it can be cleared immediately.
2593    base::MessageLoop::current()->PostTask(
2594        FROM_HERE,
2595        base::Bind(&HistoryBackend::KillHistoryDatabase, this));
2596  }
2597}
2598
2599void HistoryBackend::KillHistoryDatabase() {
2600  scheduled_kill_db_ = false;
2601  if (!db_)
2602    return;
2603
2604  // Rollback transaction because Raze() cannot be called from within a
2605  // transaction.
2606  db_->RollbackTransaction();
2607  bool success = db_->Raze();
2608  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
2609
2610#if defined(OS_ANDROID)
2611  // Release AndroidProviderBackend before other objects.
2612  android_provider_backend_.reset();
2613#endif
2614
2615  // The expirer keeps tabs on the active databases. Tell it about the
2616  // databases which will be closed.
2617  expirer_.SetDatabases(NULL, NULL);
2618
2619  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
2620  db_->BeginTransaction();
2621  CloseAllDatabases();
2622}
2623
2624void HistoryBackend::ProcessDBTask(
2625    scoped_refptr<HistoryDBTaskRequest> request) {
2626  DCHECK(request.get());
2627  if (request->canceled())
2628    return;
2629
2630  bool task_scheduled = !db_task_requests_.empty();
2631  // Make sure we up the refcount of the request. ProcessDBTaskImpl will
2632  // release when done with the task.
2633  request->AddRef();
2634  db_task_requests_.push_back(request.get());
2635  if (!task_scheduled) {
2636    // No other tasks are scheduled. Process request now.
2637    ProcessDBTaskImpl();
2638  }
2639}
2640
2641void HistoryBackend::BroadcastNotifications(
2642    int type,
2643    scoped_ptr<HistoryDetails> details) {
2644  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2645  // HistoryService -> HistoryBackend::Closing().
2646  if (delegate_)
2647    delegate_->BroadcastNotifications(type, details.Pass());
2648}
2649
2650void HistoryBackend::NotifySyncURLsModified(URLRows* rows) {
2651  if (typed_url_syncable_service_.get())
2652    typed_url_syncable_service_->OnUrlsModified(rows);
2653}
2654
2655void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2656                                           bool expired,
2657                                           URLRows* rows) {
2658  if (typed_url_syncable_service_.get())
2659    typed_url_syncable_service_->OnUrlsDeleted(all_history, expired, rows);
2660}
2661
2662// Deleting --------------------------------------------------------------------
2663
2664void HistoryBackend::DeleteAllHistory() {
2665  // Our approach to deleting all history is:
2666  //  1. Copy the bookmarks and their dependencies to new tables with temporary
2667  //     names.
2668  //  2. Delete the original tables. Since tables can not share pages, we know
2669  //     that any data we don't want to keep is now in an unused page.
2670  //  3. Renaming the temporary tables to match the original.
2671  //  4. Vacuuming the database to delete the unused pages.
2672  //
2673  // Since we are likely to have very few bookmarks and their dependencies
2674  // compared to all history, this is also much faster than just deleting from
2675  // the original tables directly.
2676
2677  // Get the bookmarked URLs.
2678  std::vector<URLAndTitle> starred_urls;
2679  HistoryClient* history_client = GetHistoryClient();
2680  if (history_client)
2681    history_client->GetBookmarks(&starred_urls);
2682
2683  URLRows kept_urls;
2684  for (size_t i = 0; i < starred_urls.size(); i++) {
2685    URLRow row;
2686    if (!db_->GetRowForURL(starred_urls[i].url, &row))
2687      continue;
2688
2689    // Clear the last visit time so when we write these rows they are "clean."
2690    row.set_last_visit(Time());
2691    row.set_visit_count(0);
2692    row.set_typed_count(0);
2693    kept_urls.push_back(row);
2694  }
2695
2696  // Clear thumbnail and favicon history. The favicons for the given URLs will
2697  // be kept.
2698  if (!ClearAllThumbnailHistory(kept_urls)) {
2699    LOG(ERROR) << "Thumbnail history could not be cleared";
2700    // We continue in this error case. If the user wants to delete their
2701    // history, we should delete as much as we can.
2702  }
2703
2704  // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
2705  // Therefore, we clear the list afterwards to make sure nobody uses this
2706  // invalid data.
2707  if (!ClearAllMainHistory(kept_urls))
2708    LOG(ERROR) << "Main history could not be cleared";
2709  kept_urls.clear();
2710
2711  db_->GetStartDate(&first_recorded_time_);
2712
2713  // Send out the notification that history is cleared. The in-memory database
2714  // will pick this up and clear itself.
2715  scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails);
2716  details->all_history = true;
2717  NotifySyncURLsDeleted(true, false, NULL);
2718  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
2719                         details.PassAs<HistoryDetails>());
2720}
2721
2722bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2723  if (!thumbnail_db_) {
2724    // When we have no reference to the thumbnail database, maybe there was an
2725    // error opening it. In this case, we just try to blow it away to try to
2726    // fix the error if it exists. This may fail, in which case either the
2727    // file doesn't exist or there's no more we can do.
2728    sql::Connection::Delete(GetFaviconsFileName());
2729
2730    // Older version of the database.
2731    sql::Connection::Delete(GetThumbnailFileName());
2732    return true;
2733  }
2734
2735  // Urls to retain mappings for.
2736  std::vector<GURL> urls_to_keep;
2737  for (URLRows::const_iterator i = kept_urls.begin();
2738       i != kept_urls.end(); ++i) {
2739    urls_to_keep.push_back(i->url());
2740  }
2741
2742  // Isolate from any long-running transaction.
2743  thumbnail_db_->CommitTransaction();
2744  thumbnail_db_->BeginTransaction();
2745
2746  // TODO(shess): If this fails, perhaps the database should be razed
2747  // or deleted.
2748  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
2749    thumbnail_db_->RollbackTransaction();
2750    thumbnail_db_->BeginTransaction();
2751    return false;
2752  }
2753
2754#if defined(OS_ANDROID)
2755  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
2756  // avaliable in HistoryBackend.
2757  db_->ClearAndroidURLRows();
2758#endif
2759
2760  // Vacuum to remove all the pages associated with the dropped tables. There
2761  // must be no transaction open on the table when we do this. We assume that
2762  // our long-running transaction is open, so we complete it and start it again.
2763  DCHECK(thumbnail_db_->transaction_nesting() == 1);
2764  thumbnail_db_->CommitTransaction();
2765  thumbnail_db_->Vacuum();
2766  thumbnail_db_->BeginTransaction();
2767  return true;
2768}
2769
2770bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
2771  // Create the duplicate URL table. We will copy the kept URLs into this.
2772  if (!db_->CreateTemporaryURLTable())
2773    return false;
2774
2775  // Insert the URLs into the temporary table.
2776  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
2777       ++i) {
2778    db_->AddTemporaryURL(*i);
2779  }
2780
2781  // Replace the original URL table with the temporary one.
2782  if (!db_->CommitTemporaryURLTable())
2783    return false;
2784
2785  // Delete the old tables and recreate them empty.
2786  db_->RecreateAllTablesButURL();
2787
2788  // Vacuum to reclaim the space from the dropped tables. This must be done
2789  // when there is no transaction open, and we assume that our long-running
2790  // transaction is currently open.
2791  db_->CommitTransaction();
2792  db_->Vacuum();
2793  db_->BeginTransaction();
2794  db_->GetStartDate(&first_recorded_time_);
2795
2796  return true;
2797}
2798
2799HistoryClient* HistoryBackend::GetHistoryClient() {
2800  if (history_client_)
2801    history_client_->BlockUntilBookmarksLoaded();
2802  return history_client_;
2803}
2804
2805void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
2806  BriefVisitInfo info;
2807  info.url_id = visit.url_id;
2808  info.time = visit.visit_time;
2809  info.transition = visit.transition;
2810  // If we don't have a delegate yet during setup or shutdown, we will drop
2811  // these notifications.
2812  if (delegate_)
2813    delegate_->NotifyVisitDBObserversOnAddVisit(info);
2814}
2815
2816#if defined(OS_ANDROID)
2817void HistoryBackend::PopulateMostVisitedURLMap() {
2818  MostVisitedURLList most_visited_urls;
2819  QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
2820                           &most_visited_urls);
2821
2822  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2823  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2824    most_visited_urls_map_[most_visited_urls[i].url] = i;
2825    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2826      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2827  }
2828}
2829
2830void HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2831  int rank = kPageVisitStatsMaxTopSites;
2832  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2833  if (it != most_visited_urls_map_.end())
2834    rank = (*it).second;
2835  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2836                            rank, kPageVisitStatsMaxTopSites + 1);
2837}
2838#endif
2839
2840}  // namespace history
2841