history_backend.cc revision 116680a4aac90f2aa7413d9095a592090648e557
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_backend.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <functional>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <list>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
17bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/files/file_enumerator.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/favicon/favicon_changed_details.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/page_usage_data.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/common/importer/imported_favicon_usage.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "components/favicon_base/select_favicon_frames.h"
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/history/core/browser/history_client.h"
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/history/core/browser/keyword_search_term.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/error_delegate_util.h"
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)/* The HistoryBackend consists of two components:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ExpireHistoryBackend (manages deleting things older than 3 months)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid RunUnlessCanceled(
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::Closure& closure,
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!is_canceled.Run())
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    closure.Run();
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(OS_ANDROID)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we keep segment data for in days. Currently 3 months.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This value needs to be greater or equal to
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dependency between MostVisitedModel and the history backend.
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kSegmentDataRetention = 90;
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kCommitIntervalSeconds = 10;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time before we re-fetch the favicon.
9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kFaviconRefetchDays = 7;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleting some.
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kMaxRedirectCount = 32;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// and is deleted.
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const int kExpireDaysThreshold = 90;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The maximum number of top sites to track when recording top page visit stats.
10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const size_t kPageVisitStatsMaxTopSites = 50;
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts from PageUsageData to MostVisitedURL. |redirects| is a
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const RedirectList& redirects) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURL mv;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.url = page_data.GetURL();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.title = page_data.GetTitle();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (redirects.empty()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirects must contain at least the target url.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects.push_back(mv.url);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects = redirects;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last url must be the target url.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mv.redirects.push_back(mv.url);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mv;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they are batched together. The important thing about this class is that
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be one of these commits still pending and holding a reference.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// task will still run (if we ever get to processing the event before
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown), but it will not do anything.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be assigned to a RunnableMethod.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in ExpireHistoryBackend).
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommitLaterTask(HistoryBackend* history_backend)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : history_backend_(history_backend) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The backend will call this function if it is being destroyed so that we
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release our reference.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_backend_ = NULL;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCommit() {
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (history_backend_.get())
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_backend_->Commit();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommitLaterTask() {}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// QueuedHistoryDBTask ---------------------------------------------------------
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
168116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQueuedHistoryDBTask::QueuedHistoryDBTask(
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<HistoryDBTask> task,
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled)
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : task_(task), origin_loop_(origin_loop), is_canceled_(is_canceled) {
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(task_);
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(origin_loop_);
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!is_canceled_.is_null());
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
178116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQueuedHistoryDBTask::~QueuedHistoryDBTask() {
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool QueuedHistoryDBTask::is_canceled() {
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return is_canceled_.Run();
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool QueuedHistoryDBTask::RunOnDBThread(HistoryBackend* backend,
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        HistoryDatabase* db) {
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return task_->RunOnDBThread(backend, db);
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid QueuedHistoryDBTask::DoneRunOnMainThread() {
191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  origin_loop_->PostTask(
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&RunUnlessCanceled,
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 base::Bind(&HistoryDBTask::DoneRunOnMainThread, task_),
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 is_canceled_));
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HistoryBackend --------------------------------------------------------------
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Delegate* delegate,
20246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               HistoryClient* history_client)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_dir_(history_dir),
2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      scheduled_kill_db_(false),
20646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      expirer_(this, history_client),
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recent_redirects_(kMaxRedirectCount),
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_destroy_message_loop_(NULL),
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_(false),
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      history_client_(history_client) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryBackend::~HistoryBackend() {
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_history_db_tasks_.clear();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sql::Connection::Delete(GetAndroidCacheFileName());
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Init(const std::string& languages, bool force_fail) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force_fail)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitImpl(languages);
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delegate_->DBLoaded();
240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  memory_pressure_listener_.reset(new base::MemoryPressureListener(
242ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PopulateMostVisitedURLMap();
245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const base::Closure& task) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null())
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_task_ = task;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Closing() {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any scheduled commit will have a reference to us, we must make it
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release that reference before we can be destroyed.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release our reference to the delegate, this reference will be keeping the
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // history service alive.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void HistoryBackend::ClearCachedDataForContextID(ContextID context_id) {
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  tracker_.ClearCachedDataForContextID(context_id);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetThumbnailFileName() const {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kThumbnailsFilename);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetFaviconsFileName() const {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kFaviconsFilename);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetArchivedFileName() const {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kArchivedHistoryFilename);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kAndroidCacheFilename);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is used to detect referrer loops.  Should not happen, but can
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the database is corrupt.
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = from_visit;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (visit_id) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitRow row;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForVisit(visit_id, &row))
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row.segment_id)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return row.segment_id;  // Found a visit in this change with a segment.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the referrer of this visit, if any.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_id = row.referring_visit;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(visit_id) != visit_set.end()) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in referer chain, giving up";
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(visit_id);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::UpdateSegments(
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID from_visit,
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID visit_id,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition_type,
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time ts) {
318b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only consider main frames.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!content::PageTransitionIsMainFrame(transition_type))
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SegmentID segment_id = 0;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition t =
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition_type);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are we at the beginning of a new segment?
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that navigating to an existing entry (with back/forward) reuses the
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same transition type.  We are not adding it as a new segment in that case
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because if this was the target of a redirect, we might end up with
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2 entries for the same final URL. Ex: User types google.net, gets
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirected to google.com. A segment is created for google.net. On
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // google.com users navigates through a link, then press back. That last
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation is for the entry google.com transition typed. We end up adding
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a segment for that one as well. So we end up with google.net and google.com
33858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // in the segment table, showing as 2 entries in the NTP.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note also that we should still be updating the visit count for that segment
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which we are not doing now. It should be addressed when
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://crbug.com/96860 is fixed.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((t == content::PAGE_TRANSITION_TYPED ||
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If so, create or get the segment.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string segment_name = db_->ComputeSegmentName(url);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    segment_id = db_->GetSegmentNamed(segment_name);
352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!segment_id) {
353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      segment_id = db_->CreateSegment(url_id, segment_name);
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!segment_id) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: if we update an existing segment, we update the url used to
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // represent that segment in order to minimize stale most visited
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // images.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: it is possible there is no segment ID set for this visit chain.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TYPED. (For example GENERATED). In this case this visit doesn't count
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // toward any segment.
369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    segment_id = GetLastSegmentID(from_visit);
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!segment_id)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the segment in the visit.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->SetSegmentID(visit_id, segment_id)) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, increase the counter for that segment / day.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return segment_id;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void HistoryBackend::UpdateWithPageEndTime(ContextID context_id,
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int32 page_id,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const GURL& url,
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Time end_ts) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  VisitID visit_id = tracker_.GetLastVisit(context_id, page_id, url);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisitDuration(visit_id, end_ts);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
398b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the starting visit_time for visit_id.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_row;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetRowForVisit(visit_id, &visit_row)) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should never have a negative duration time even when time is skewed.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_row.visit_duration = end_ts > visit_row.visit_time ?
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateVisitRow(visit_row);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
412b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
417f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      request.context_id, request.page_id, request.referrer));
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID from_visit_id = last_ids.second;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a redirect chain is given, we expect the last item in that chain to be
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the final URL.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request.redirects.empty() ||
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         request.redirects.back() == request.url);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is adding older history, we need to make sure our times
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are correct.
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request.time < first_recorded_time_)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = request.time;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition request_transition = request.transition;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition stripped_transition =
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransitionStripQualifier(request_transition);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_generated =
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is navigating to a not-previously-typed intranet hostname,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the transition to TYPED so that the omnibox will learn that this is
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a known host.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_redirects = request.redirects.size() > 1;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (content::PageTransitionIsMainFrame(request_transition) &&
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url(has_redirects ?
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request.redirects[0] : request.url);
446010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (origin_url.SchemeIs(url::kHttpScheme) ||
447010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        origin_url.SchemeIs(url::kHttpsScheme) ||
448cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        origin_url.SchemeIs(url::kFtpScheme)) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string host(origin_url.host());
450a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      size_t registry_length =
451a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          net::registry_controlled_domains::GetRegistryLength(
452a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              host,
453a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
454a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
455a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (registry_length == 0 && !db_->IsTypedHost(host)) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stripped_transition = content::PAGE_TRANSITION_TYPED;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition =
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::PageTransitionFromInt(
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                stripped_transition |
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                content::PageTransitionGetQualifier(request_transition));
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_redirects) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The single entry is both a chain start and end.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition t = content::PageTransitionFromInt(
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition |
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START |
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_END);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect case (one element means just the page itself).
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_ids = AddPageVisit(request.url, request.time,
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            last_ids.second, t, request.visit_source);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the segment for this visit. KEYWORD_GENERATED visits should not
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result in changing most visited, so we don't update segments (most
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // visited db).
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_keyword_generated) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     request.time);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the referrer's duration.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateVisitDuration(from_visit_id, request.time);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirect case. Add the redirect chain.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition redirect_info =
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects = request.redirects;
493f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (redirects[0].SchemeIs(url::kAboutScheme)) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the redirect source + referrer is "about" we skip it. This
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // happens when a page opens a new frame/window to about:blank and then
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // script sets the URL to somewhere else (used to hide the referrer). It
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would be nice to keep all these redirects properly but we don't ever
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // see the initial about:blank load, so we don't know where the
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // subsequent client redirect came from.
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this case, we just don't bother hooking up the source of the
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects, so we remove it.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirects.erase(redirects.begin());
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The first entry in the redirect chain initiated a client redirect.
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't add this to the database since the referrer is already
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // there, so we skip over it but change the transition type of the first
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transition to client redirect.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The referrer is invalid when restoring a session that features an
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // https tab that redirects to a different host or to http. In this
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case we don't need to reconnect the new redirect with the existing
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // chain.
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (request.referrer.is_valid()) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(request.referrer == redirects[0]);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        redirects.erase(redirects.begin());
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the navigation entry for this visit has replaced that for the
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // first visit, remove the CHAIN_END marker from the first visit. This
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can be called a lot, for example, the page cycler, and most of the
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // time we won't have changed anything.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisitRow visit_row;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (request.did_replace_entry &&
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db_->GetRowForVisit(last_ids.second, &visit_row) &&
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          visit_row.transition = content::PageTransitionFromInt(
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->UpdateVisitRow(visit_row);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t redirect_index = 0; redirect_index < redirects.size();
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         redirect_index++) {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransition t =
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::PageTransitionFromInt(stripped_transition | redirect_info);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If this is the last transition, add a CHAIN_END marker
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (redirect_index == (redirects.size() - 1)) {
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t = content::PageTransitionFromInt(
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            t | content::PAGE_TRANSITION_CHAIN_END);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Record all redirect visits with the same timestamp. We don't display
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them anyway, and if we ever decide to, we can reconstruct their order
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the redirect chain.
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_ids = AddPageVisit(redirects[redirect_index],
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              request.time, last_ids.second,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              t, request.visit_source);
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (t & content::PAGE_TRANSITION_CHAIN_START) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the segment for this visit.
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateSegments(redirects[redirect_index],
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       from_visit_id, last_ids.second, t, request.time);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the visit_details for this visit.
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateVisitDuration(from_visit_id, request.time);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Subsequent transitions in the redirect list must all be server
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects.
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last, save this redirect chain for later so we can set titles & favicons
566bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // on the redirected pages properly.
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recent_redirects_.Put(request.url, redirects);
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the last visit to the tracker so we can get outgoing transitions.
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation anyway, so last_visit_id is always zero for them.  But adding
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them here confuses main frame history, so we skip them for now.
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
580f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    tracker_.AddVisit(request.context_id, request.page_id, request.url,
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      last_ids.second);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::InitImpl(const std::string& languages) {
588b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!db_) << "Initializing HistoryBackend twice";
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the rare case where the db fails to initialize a dialog may get shown
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the blocks the caller, yet allows other messages through. For this reason
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only set db_ to the created database if creation is successful. That
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way other methods won't do anything as db_ is still NULL.
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
596bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Compute the file names.
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
5983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::FilePath thumbnail_name = GetFaviconsFileName();
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath archived_name = GetArchivedFileName();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
601bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete the old index database files which are no longer used.
602bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DeleteFTSIndexDatabases();
603bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // History database.
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new HistoryDatabase());
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Unretained to avoid a ref loop with db_.
6087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  db_->set_error_callback(
6097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Bind(&HistoryBackend::DatabaseErrorCallback,
6107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                 base::Unretained(this)));
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  sql::InitStatus status = db_->Init(history_name);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_OK:
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_FAILURE: {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A NULL db_ will cause all calls on this object to notice this error
6187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // and to not continue. If the error callback scheduled killing the
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database, the task it posted has not executed yet. Try killing the
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database now before we close it.
6217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      bool kill_db = scheduled_kill_db_;
6227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (kill_db)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        KillHistoryDatabase();
6247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
625a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->NotifyProfileError(status);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the in-memory database and send it back to the history service on the
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // main thread.
635a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  {
636a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<InMemoryHistoryBackend> mem_backend(new InMemoryHistoryBackend);
637116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (mem_backend->Init(history_name))
638a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->SetInMemoryBackend(mem_backend.Pass());
639a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Thumbnail database.
6433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): "thumbnail database" these days only stores
6443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // favicons.  Thumbnails are stored in "top sites".  Consider
6453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // renaming "thumbnail" references to "favicons" or something of the
6463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // sort.
647116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  thumbnail_db_.reset(new ThumbnailDatabase(history_client_));
6484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unlike the main database, we don't error out when the database is too
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new because this error is much less severe. Generally, this shouldn't
65158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // happen since the thumbnail and main database versions should be in sync.
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We'll just continue without thumbnails & favicons in this case or any
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other error.
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the thumbnail database.";
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Nuke any files corresponding to the legacy Archived History Database, which
65946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // previously retained expired (> 3 months old) history entries, but, in the
66046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // end, was not used for much, and consequently has been removed as of M37.
66146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(engedy): Remove this code after the end of 2014.
66246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  sql::Connection::Delete(archived_name);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Generate the history and thumbnail database metrics only after performing
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any migration work.
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::RandInt(1, 100) == 50) {
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only do this computation sometimes since it can be expensive.
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->ComputeDatabaseMetrics(history_name);
6692385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (thumbnail_db_)
6702385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      thumbnail_db_->ComputeDatabaseMetrics();
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
67346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.SetDatabases(db_.get(), thumbnail_db_.get());
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the long-running transaction.
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
677b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the first item in our database.
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start expiring old stuff.
68446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.StartExpiringOldStuff(TimeDelta::FromDays(kExpireDaysThreshold));
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
687b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
68846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    android_provider_backend_.reset(
68946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        new AndroidProviderBackend(GetAndroidCacheFileName(),
69046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   db_.get(),
69146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   thumbnail_db_.get(),
69246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   history_client_,
69346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   delegate_.get()));
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HISTOGRAM_TIMES("History.InitTime",
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  TimeTicks::Now() - beginning_time);
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
701ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid HistoryBackend::OnMemoryPressure(
702ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
703ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool trim_aggressively = memory_pressure_level ==
704ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
705ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (db_)
706ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    db_->TrimMemory(trim_aggressively);
707ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (thumbnail_db_)
708ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    thumbnail_db_->TrimMemory(trim_aggressively);
709ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
710ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloseAllDatabases() {
712b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the long-running transaction.
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->CommitTransaction();
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset();
71658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Forget the first recorded time since the database is closed.
71758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    first_recorded_time_ = base::Time();
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
719b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time time,
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID referring_visit,
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitSource visit_source) {
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Top-level frame navigations are visible, everything else is hidden
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool new_hidden = !content::PageTransitionIsMainFrame(transition);
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This code must stay in sync with
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExpireHistoryBackend::ExpireURLsForVisits().
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // typed, which would eliminate the need for this code.
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int typed_increment = 0;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition transition_type =
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((transition_type == content::PAGE_TRANSITION_TYPED &&
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !content::PageTransitionIsRedirect(transition)) ||
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typed_increment = 1;
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
746eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Only count the page visit if it came from user browsing and only count it
748eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // once when cycling through a redirect chain.
749eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (visit_source == SOURCE_BROWSED &&
750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordTopPageVisitStats(url);
752eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
753eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if this URL is already in the DB.
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update of an existing row.
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::PageTransitionStripQualifier(transition) !=
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_RELOAD)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_visit_count(url_info.visit_count() + 1);
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (typed_increment)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_typed_count(url_info.typed_count() + typed_increment);
765c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (url_info.last_visit() < time)
766c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_info.set_last_visit(time);
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only allow un-hiding of pages, never hiding.
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_hidden)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_hidden(false);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateURLRow(url_id, url_info);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Addition of a new row.
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_visit_count(1);
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_typed_count(typed_increment);
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_last_visit(time);
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_hidden(new_hidden);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_id = db_->AddURL(url_info);
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Adding URL failed.";
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::make_pair(0, 0);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.id_ = url_id;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the visit with the time to the database.
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyVisitObservers(visit_info);
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_info.visit_time < first_recorded_time_)
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = visit_info.visit_time;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification of the visit.
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id) {
798b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
799b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
800b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
801a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<URLVisitedDetails> details(new URLVisitedDetails);
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->transition = transition;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->row = url_info;
804cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    details->visit_time = time;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
807116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // QueryRedirectsTo(url, &details->redirects);
808a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED,
809a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
820b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
82746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // As of M37, we no longer maintain an archived database, ignore old visits.
82846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit()))
82946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
83246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    URLID url_id = db_->GetRowForURL(i->url(), &existing_url);
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
83546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      url_id = db_->AddURL(*i);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
841f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      modified->changed_urls.push_back(*i);
842f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      modified->changed_urls.back().set_id(url_id);  // i->id_ is likely 0.
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          content::PageTransitionFromInt(
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_LINK |
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_START |
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_END), 0);
85346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!db_->AddVisit(&visit_info, visit_source)) {
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (typed_url_syncable_service_.get())
865b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
866b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
873a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         modified.PassAs<HistoryDetails>());
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
87946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return time < expirer_.GetCurrentExpirationTime();
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
882a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url,
883a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  const base::string16& title) {
884b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
920b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
921b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
923a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
929a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               const base::string16& title) {
930b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_info.set_title(base::UTF8ToUTF16(url.spec()));
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
95490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
956b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
971b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
977b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int max_visits,
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               VisitVector* visits) {
985b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
990116680a4aac90f2aa7413d9095a592090648e557Ben Murdochsize_t HistoryBackend::UpdateURLs(const history::URLRows& urls) {
991116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
992116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return 0;
993116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
994116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
995116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (history::URLRows::const_iterator it = urls.begin(); it != urls.end();
996116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++it) {
997116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(it->id());
998116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (db_->UpdateURLRow(it->id(), *it))
999116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      details->changed_urls.push_back(*it);
1000116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1001116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1002116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Broadcast notifications for any URLs that have actually been changed. This
1003116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // will update the in-memory database and the InMemoryURLIndex.
1004116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t num_updated_records = details->changed_urls.size();
1005116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (num_updated_records) {
1006116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (typed_url_syncable_service_)
1007116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
1008116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1009116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           details.PassAs<HistoryDetails>());
1010116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ScheduleCommit();
1011116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1012116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return num_updated_records;
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::AddVisits(const GURL& url,
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<VisitInfo>& visits,
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               VisitSource visit_source) {
1018b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         visit != visits.end(); ++visit) {
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!AddPageVisit(
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              url, visit->first, 0, visit->second, visit_source).first) {
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1033b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.ExpireVisits(visits);
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VisitSourceMap* sources) {
1043b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetVisitsSource(visits, sources);
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1051b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetRowForURL(url, url_row) != 0;
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1056116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryURL(const GURL& url,
1057116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                              bool want_visits,
1058116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                              QueryURLResult* result) {
1059116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(result);
1060116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->success = db_ && db_->GetRowForURL(url, &result->row);
1061f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Optionally query the visits.
1062116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (result->success && want_visits)
1063116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    db_->GetVisitsForURL(result->row.id(), &result->visits);
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1066b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1067b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return typed_url_syncable_service_.get();
1068b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1069b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keyword visits --------------------------------------------------------------
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
1073116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 KeywordID keyword_id,
1074a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                 const base::string16& term) {
1075b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the ID for this URL.
10790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  URLRow row;
10800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!db_->GetRowForURL(url, &row)) {
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a small possibility the url was deleted before the keyword
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was added. Ignore the request.
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  db_->SetKeywordSearchTermsForURL(row.id(), keyword_id, term);
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(
10890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1090a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      scoped_ptr<HistoryDetails>(
10910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          new KeywordSearchUpdatedDetails(row, keyword_id, term)));
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
1096b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->DeleteAllSearchTermsForKeyword(keyword_id);
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void HistoryBackend::DeleteKeywordSearchTermForURL(const GURL& url) {
11040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!db_)
11050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, NULL);
11080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!url_id)
11090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  db_->DeleteKeywordSearchTermForURL(url_id);
11110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  BroadcastNotifications(
11130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
11140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_ptr<HistoryDetails>(new KeywordSearchDeletedDetails(url_id)));
11150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScheduleCommit();
11160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
11170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1118116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
11195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  const base::string16& term) {
11205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_)
11215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
11225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<KeywordSearchTermRow> rows;
11245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_->GetKeywordSearchTermRows(term, &rows)) {
11255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<GURL> items_to_delete;
11265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLRow row;
11275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (std::vector<KeywordSearchTermRow>::iterator it = rows.begin();
11285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it != rows.end(); ++it) {
11295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if ((it->keyword_id == keyword_id) && db_->GetURLRow(it->url_id, &row))
11305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        items_to_delete.push_back(row.url());
11315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
11325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DeleteURLs(items_to_delete);
11335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
11345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
11355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Downloads -------------------------------------------------------------------
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)uint32 HistoryBackend::GetNextDownloadId() {
1139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return db_ ? db_->GetNextDownloadId() : content::DownloadItem::kInvalidId;
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get all the download entries from the database.
11432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QueryDownloads(rows);
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update a particular download entry.
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->UpdateDownload(data);
11532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HistoryBackend::CreateDownload(const history::DownloadRow& history_info) {
1157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
1158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
1159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool success = db_->CreateDownload(history_info);
11602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
1161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return success;
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_before = db_->CountDownloads();
11682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks started_removing = base::TimeTicks::Now();
11692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HistoryBackend uses a long-running Transaction that is committed
11702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // periodically, so this loop doesn't actually hit the disk too hard.
11717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::set<uint32>::const_iterator it = ids.begin();
11727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       it != ids.end(); ++it) {
11732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->RemoveDownload(*it);
11742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScheduleCommit();
11762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks finished_removing = base::TimeTicks::Now();
11777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_after = db_->CountDownloads();
11787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
11797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_LE(downloads_count_after, downloads_count_before);
11807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (downloads_count_after > downloads_count_before)
11817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
11827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
11837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
11847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        num_downloads_deleted);
11857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeDelta micros = (1000 * (finished_removing - started_removing));
11867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
11877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (num_downloads_deleted > 0) {
11887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
11897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        (1000 * micros) / num_downloads_deleted);
11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GE(ids.size(), num_downloads_deleted);
11927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (ids.size() < num_downloads_deleted)
11937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
11947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
11957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        ids.size() - num_downloads_deleted);
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1198116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryHistory(const base::string16& text_query,
1199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  const QueryOptions& options,
1200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  QueryResults* query_results) {
1201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(query_results);
1202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeTicks beginning_time = base::TimeTicks::Now();
1203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (text_query.empty()) {
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Basic history query for the main database.
1206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      QueryHistoryBasic(options, query_results);
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Text history query.
1209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      QueryHistoryText(text_query, options, query_results);
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.QueryHistory",
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic time-based querying of history.
121746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void HistoryBackend::QueryHistoryBasic(const QueryOptions& options,
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QueryResults* result) {
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First get all visits.
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
122146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool has_more_results = db_->GetVisibleVisitsInRange(options, &visits);
12222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add them and the URL rows to the results.
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); i++) {
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VisitRow visit = visits[i];
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add a result row for this visit, get the URL info from the DB.
123046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!db_->GetURLRow(visit.url_id, &url_result)) {
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to get id " << visit.url_id
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " from history.urls.";
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // DB out of sync and URL doesn't exist, try to recover.
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid()) {
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Got invalid URL from history.urls with id "
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << visit.url_id << ":  "
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << url_result.url().possibly_invalid_spec();
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(visit.visit_time);
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Set whether the visit was blocked for a managed user by looking at the
1246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // transition type.
1247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url_result.set_blocked_visit(
1248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't set any of the query-specific parts of the URLResult, since
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // snippets and stuff don't apply to basic querying.
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_more_results && options.begin_time <= first_recorded_time_)
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Text-based querying of history.
126046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void HistoryBackend::QueryHistoryText(const base::string16& text_query,
1261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const QueryOptions& options,
1262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      QueryResults* result) {
1263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  URLRows text_matches;
126446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  db_->GetTextMatches(text_query, &text_matches);
1265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<URLResult> matching_visits;
1267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VisitVector visits;    // Declare outside loop to prevent re-construction.
1268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < text_matches.size(); i++) {
1269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const URLRow& text_match = text_matches[i];
1270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Get all visits for given URL match.
127146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    db_->GetVisibleVisitsForURL(text_match.id(), options, &visits);
1272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < visits.size(); j++) {
1273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      URLResult url_result(text_match);
1274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_result.set_visit_time(visits[j].visit_time);
1275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      matching_visits.push_back(url_result);
1276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::sort(matching_visits.begin(), matching_visits.end(),
1280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            URLResult::CompareVisitTime);
1281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t max_results = options.max_count == 0 ?
1283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (std::vector<URLResult>::iterator it = matching_visits.begin();
1285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != matching_visits.end() && result->size() < max_results; ++it) {
1286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->AppendURLBySwapping(&(*it));
1287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (matching_visits.size() == result->size() &&
1290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      options.begin_time <= first_recorded_time_)
1291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->set_reached_beginning(true);
1292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1294116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryRedirectsFrom(const GURL& from_url,
1295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        RedirectList* redirects) {
1296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  redirects->clear();
1297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
1301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
1302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!cur_visit)
1303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;  // No visits for URL.
1304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GetRedirectsFromSpecificVisit(cur_visit, redirects);
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1308116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryRedirectsTo(const GURL& to_url,
1309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      RedirectList* redirects) {
1310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  redirects->clear();
1311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
1315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
1316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!cur_visit)
1317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;  // No visits for URL.
1318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GetRedirectsToSpecificVisit(cur_visit, redirects);
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetVisibleVisitCountToHost(
1323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const GURL& url,
1324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    VisibleVisitCountToHostResult* result) {
1325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->count = 0;
1326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->success = db_.get() &&
1327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                    db_->GetVisibleVisitCountToHost(
1328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        url, &result->count, &result->first_visit);
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1331116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryMostVisitedURLs(int result_count,
1332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          int days_back,
1333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          MostVisitedURLList* result) {
1334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
1338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  db_->QuerySegmentUsage(
1339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Time::Now() - base::TimeDelta::FromDays(days_back),
1340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      result_count,
1341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &data.get());
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
1344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PageUsageData* current_data = data[i];
1345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RedirectList redirects;
1346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QueryRedirectsFrom(current_data->GetURL(), &redirects);
1347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
1348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result->push_back(url);
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1352116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryFilteredURLs(int result_count,
1353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       const history::VisitFilter& filter,
1354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       bool extended_info,
1355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       history::FilteredURLList* result) {
1356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(result);
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time request_start = base::Time::Now();
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->clear();
1360b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, double> score_map;
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); ++i) {
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(georgey): experiment with visit_segment database granularity (it is
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently 24 hours) to use it directly instead of using visits database,
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is considerably slower.
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.reserve(score_map.size());
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<URLID, double>::iterator it = score_map.begin();
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != score_map.end(); ++it) {
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* pud = new PageUsageData(it->first);
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pud->SetScore(it->second);
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.push_back(pud);
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit to the top |result_count| results.
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
13872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_count && implicit_cast<int>(data.size()) > result_count)
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.resize(result_count);
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow info;
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetURLRow(data[i]->GetID(), &info)) {
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetURL(info.url());
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetTitle(info.title());
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilteredURL url(*current_data);
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extended_info) {
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitVector visits;
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisitsForURL(current_data->GetID(), &visits);
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits.size() > 0) {
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url.extended_info.total_visits = visits.size();
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < visits.size(); ++i) {
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url.extended_info.duration_opened +=
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visits[i].visit_duration.InSeconds();
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (visits[i].visit_time > url.extended_info.last_visit_time) {
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url.extended_info.last_visit_time = visits[i].visit_time;
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(macourteau): implement the url.extended_info.visits stat.
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result->push_back(url);
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta_time = std::max(1, std::min(999,
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATIC_HISTOGRAM_POINTER_BLOCK(
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NewTabPage.SuggestedSitesLoadTime",
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Add(delta_time),
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsFromSpecificVisit(
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit, history::RedirectList* redirects) {
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow any redirects from the given visit and add them to the list.
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It *should* be impossible to get a circular chain here, but we check
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just in case to avoid infinite loops.
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsToSpecificVisit(
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit,
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow redirects going to cur_visit. These are added to |redirects| in
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the order they are found. If a redirect chain looks like A -> B -> C and
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |cur_visit| = C, redirects will be {B, A} in that order.
1453b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1469116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::ScheduleAutocomplete(const base::Callback<
1470116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    void(history::HistoryBackend*, history::URLDatabase*)>& callback) {
1471116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  callback.Run(this, db_.get());
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1474bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid HistoryBackend::DeleteFTSIndexDatabases() {
1475bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Find files on disk matching the text databases file pattern so we can
1476bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // quickly test for and delete them.
1477bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath::StringType filepattern =
1478bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FILE_PATH_LITERAL("History Index *");
1479bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FileEnumerator enumerator(
1480bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      history_dir_, false, base::FileEnumerator::FILES, filepattern);
1481bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  int num_databases_deleted = 0;
1482bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath current_file;
1483bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  while (!(current_file = enumerator.Next()).empty()) {
1484bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (sql::Connection::Delete(current_file))
1485bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      num_databases_deleted++;
1486bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1487bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1488bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                       num_databases_deleted);
1489bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
1490bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFavicons(
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
14946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1495f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
14966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types, desired_sizes,
14972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void HistoryBackend::GetLargestFaviconForURL(
15010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const GURL& page_url,
15020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<int>& icon_types,
15030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int minimum_size_in_pixels,
1504f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult* favicon_bitmap_result) {
15058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(favicon_bitmap_result);
15068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
15088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
15118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
15138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
15148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      icon_mappings.empty())
15158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int required_icon_types = 0;
15188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator i = icon_types.begin();
15198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_types.end(); ++i) {
15208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    required_icon_types |= *i;
15218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find the largest bitmap for each IconType placing in
15248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // |largest_favicon_bitmaps|.
15250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::map<favicon_base::IconType, FaviconBitmap> largest_favicon_bitmaps;
15268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
15278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_mappings.end(); ++i) {
15288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!(i->icon_type & required_icon_types))
15298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      continue;
15308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
15318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
15328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
15338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (std::vector<FaviconBitmapIDSize>::const_iterator j =
15348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)             bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
15358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (largest.bitmap_id == 0 ||
15368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest.pixel_size.width() < j->pixel_size.width() &&
15378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           largest.pixel_size.height() < j->pixel_size.height())) {
15388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.icon_id = i->icon_id;
15398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.bitmap_id = j->bitmap_id;
15408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.pixel_size = j->pixel_size;
15418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
15428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
15438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (largest_favicon_bitmaps.empty())
15458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find an icon which is larger than minimum_size_in_pixels in the order of
15488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // icon_types.
15498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FaviconBitmap largest_icon;
15508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator t = icon_types.begin();
15518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       t != icon_types.end(); ++t) {
15520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (std::map<favicon_base::IconType, FaviconBitmap>::const_iterator f =
15530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             largest_favicon_bitmaps.begin();
15540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         f != largest_favicon_bitmaps.end();
15550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++f) {
15568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (f->first & *t &&
15578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest_icon.bitmap_id == 0 ||
15588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
15598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
15608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon = f->second;
15618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
15628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
15638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
15648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon.pixel_size.height() > minimum_size_in_pixels)
15658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
15668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  GURL icon_url;
15690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
15708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
15718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &icon_type)) {
15728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::Time last_updated;
1576f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  favicon_base::FaviconRawBitmapResult bitmap_result;
15778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_url = icon_url;
15788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_type = icon_type;
15798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
15808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &last_updated,
15818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.bitmap_data,
15828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.pixel_size)) {
15838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.expired = (Time::Now() - last_updated) >
15878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      TimeDelta::FromDays(kFaviconRefetchDays);
15888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (bitmap_result.is_valid())
15898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    *favicon_bitmap_result = bitmap_result;
15908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
15928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                  TimeTicks::Now() - beginning_time);
15938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
15948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFaviconsForURL(
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
15986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1599f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
16002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_results);
16016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  GetFaviconsFromDB(page_url, icon_types, desired_sizes, bitmap_results);
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetFaviconForID(
16050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id,
16066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    int desired_size,
1607f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
16080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_ids.push_back(favicon_id);
16106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  std::vector<int> desired_sizes;
16116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  desired_sizes.push_back(desired_size);
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get results from DB.
16142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids,
16156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                      desired_sizes,
16162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bitmap_results);
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetch(
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1624f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
16252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
16266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                    desired_sizes, bitmap_results);
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MergeFavicon(
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
16312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url,
16320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
1635b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID favicon_id =
163990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!favicon_id) {
16422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is no favicon at |icon_url|, create it.
1643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
16442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
16472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
16502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // replace it.
16512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bitmap_identical = false;
16522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool replaced_bitmap = false;
16532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
16542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
16552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
16562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
16572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
16582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bitmap_identical = true;
16592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
16602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
16612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_data, base::Time::Now());
16622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        replaced_bitmap = true;
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
16642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a vector of the pixel sizes of the favicon bitmaps currently at
16692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url|.
16702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
16712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
16722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!replaced_bitmap && !bitmap_identical) {
16752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
16762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmaps are not consistent with the merged in data.
16772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delete an arbitrary favicon bitmap to avoid going over the limit of
16802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |kMaxFaviconBitmapsPerIconURL|.
16812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
16822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
16832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.erase(favicon_sizes.begin());
16842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
16852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
16862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    pixel_size);
16872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(pixel_size);
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A site may have changed the favicons that it uses for |page_url|.
16912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Example Scenario:
16922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   page_url = news.google.com
169358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //   Initial State: www.google.com/favicon.ico 16x16, 32x32
16942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
16952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //                ..., 16x16)
16962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
16972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulties:
16982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1. Sync requires that a call to GetFaviconsForURL() returns the
16992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    |bitmap_data| passed into MergeFavicon().
17002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
17012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      stay mapped to news.google.com because it would be unclear which 16x16
17022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      bitmap should be returned via GetFaviconsForURL().
17032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2. www.google.com/favicon.ico may be mapped to more than just
17052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    news.google.com (eg www.google.com).
17062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
17072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To resolve these problems, we copy all of the favicon bitmaps previously
17092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mapped to news.google.com (|page_url|) and add them to the favicon at
17102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
17112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url| are set to default to indicate that |icon_url| has incomplete
17122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // / incorrect data.
171358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
17142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //              news.google.com
17152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
17162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //               modified.
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
17192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
17222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
17232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i) {
17242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
17252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (icon_mappings[i].icon_url == icon_url)
17282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmap> bitmaps_to_copy;
17312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
17322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     &bitmaps_to_copy);
17332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
17342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Do not add a favicon bitmap at a pixel size for which there is already
17352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // a favicon bitmap mapped to |icon_url|. The one there is more correct
17362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // and having multiple equally sized favicon bitmaps for |page_url| is
17372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ambiguous in terms of GetFaviconsForURL().
17382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
17392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
17402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != favicon_sizes.end())
17412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
17422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add the favicon bitmap as expired as it is not consistent with the
17442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // merged in data.
17452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->AddFaviconBitmap(favicon_id,
17462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].bitmap_data, base::Time(),
17472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].pixel_size);
17482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
17492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
17512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
17522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
17532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
17542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the favicon mappings such that only |icon_url| is mapped to
17562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |page_url|.
17572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool mapping_changed = false;
17582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
17590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID> favicon_ids;
17602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_ids.push_back(favicon_id);
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
17622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mapping_changed = true;
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (mapping_changed || !bitmap_identical)
17662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFavicons(
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
1773f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapData>&
1774f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        favicon_bitmap_data) {
1775b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1780f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Build map of FaviconRawBitmapData for each icon url.
1781f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  typedef std::map<GURL, std::vector<favicon_base::FaviconRawBitmapData> >
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BitmapDataByIconURL;
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitmapDataByIconURL grouped_by_icon_url;
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track whether the method modifies or creates any favicon bitmaps, favicons
17902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // or icon mappings.
17912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool data_modified = false;
17922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> icon_ids;
17942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
17952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != grouped_by_icon_url.end(); ++it) {
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = it->first;
17970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id =
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
17992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!icon_id) {
18012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Remove the favicon sizes attribute from
18022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ThumbnailDatabase::AddFavicon().
1803eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
18042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_modified = true;
18052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_ids.push_back(icon_id);
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!data_modified)
18092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, &data_modified);
18102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
18112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, NULL);
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_modified |=
18152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_modified) {
18182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Send notification to the UI as an icon mapping, favicon, or favicon
18192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmap was changed by this function.
18202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
18212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1828b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ ||
18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &icon_mappings))
18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloneFavicons(const GURL& old_page_url,
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& new_page_url) {
1842b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent cross-domain cloning.
18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetImportedFavicons(
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ImportedFaviconUsage>& favicon_usage) {
1855b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Track all URLs that had their favicons set or updated.
18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> favicons_changed;
18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_usage.size(); i++) {
18640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id =
18650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        thumbnail_db_->GetFaviconIDForFaviconURL(
18660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            favicon_usage[i].favicon_url, favicon_base::FAVICON, NULL);
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_id) {
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This favicon doesn't exist yet, so we create it using the given data.
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkotwicz): Pass in real pixel size.
18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_id = thumbnail_db_->AddFavicon(
18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_usage[i].favicon_url,
18720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          favicon_base::FAVICON,
18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new base::RefCountedBytes(favicon_usage[i].png_data),
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          now,
18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::Size());
18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the mapping from all the URLs to the favicon.
187946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    HistoryClient* history_client = GetHistoryClient();
18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url != favicon_usage[i].urls.end(); ++url) {
18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow url_row;
18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!db_->GetRowForURL(*url, &url_row)) {
18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the URL is present as a bookmark, add the url in history to
18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // save the favicon mapping. This will match with what history db does
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for regular bookmarked URLs with favicons - when history db is
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // cleaned, we keep an entry in the db with 0 visits as long as that
18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // url is bookmarked.
188946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        if (history_client && history_client->IsBookmarked(*url)) {
18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          URLRow url_info(*url);
18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_visit_count(0);
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_typed_count(0);
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_last_visit(base::Time());
18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_hidden(false);
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->AddURL(url_info);
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
190090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!thumbnail_db_->GetIconMappingsForPageURL(
19010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                *url, favicon_base::FAVICON, NULL)) {
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // URL is present in history, update the favicon *only* if it is not
19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // set already.
19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!favicons_changed.empty()) {
19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the notification about the changed favicon URLs.
1913a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<FaviconChangedDetails> changed_details(
1914a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new FaviconChangedDetails);
19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.swap(favicons_changed);
19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
1917a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           changed_details.PassAs<HistoryDetails>());
19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* page_url,
19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
19256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1926f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |page_url| is specified, |icon_types| must be either a single icon
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type or icon types which are equivalent.
19290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!page_url || icon_types == favicon_base::FAVICON ||
19300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_ICON ||
19310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_PRECOMPOSED_ICON ||
19320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types ==
19330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             (favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON));
19342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bitmap_results->clear();
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1936b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The icon type for which the mappings will the updated and data will be
19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned.
19440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType selected_icon_type = favicon_base::INVALID_ICON;
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_urls.size(); ++i) {
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = icon_urls[i];
19480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type_out;
19490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const favicon_base::FaviconID favicon_id =
195090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(
195190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            icon_url, icon_types, &icon_type_out);
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_id) {
19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Return and update icon mappings only for the largest icon type. As
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if an |icon_url| with a larger icon type is found.
19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out > selected_icon_type) {
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_icon_type = icon_type_out;
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.clear();
19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out == selected_icon_type)
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.push_back(favicon_id);
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_url && !favicon_ids.empty()) {
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool mappings_updated =
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              favicon_ids);
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappings_updated) {
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommit();
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_sizes,
19776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      bitmap_results);
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconBitmaps(
19810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id,
1982f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapData>& favicon_bitmap_data,
19832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* favicon_bitmaps_changed) {
19842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_bitmaps_changed)
19852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *favicon_bitmaps_changed = false;
19862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1990f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<favicon_base::FaviconRawBitmapData> to_add = favicon_bitmap_data;
19912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
19932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
1994f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapData>::iterator match_it =
19950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        to_add.end();
1996f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (std::vector<favicon_base::FaviconRawBitmapData>::iterator it =
19970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             to_add.begin();
19980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         it != to_add.end();
19990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++it) {
20002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->pixel_size == pixel_size) {
20012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        match_it = it;
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
20072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (match_it == to_add.end()) {
20082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
20092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed)
20112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *favicon_bitmaps_changed = true;
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
20132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed &&
20142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !*favicon_bitmaps_changed &&
20152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
20162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
20172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id, base::Time::Now());
20182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
20192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
20202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Time::Now());
20212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (favicon_bitmaps_changed)
20232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *favicon_bitmaps_changed = true;
20242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
20252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      to_add.erase(match_it);
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < to_add.size(); ++i) {
20302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
20312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time::Now(), to_add[i].pixel_size);
20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_bitmaps_changed)
20342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *favicon_bitmaps_changed = true;
20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool HistoryBackend::ValidateSetFaviconsParams(const std::vector<
2039f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapData>& favicon_bitmap_data) const {
20402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<GURL, size_t> BitmapsPerIconURL;
20412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BitmapsPerIconURL num_bitmaps_per_icon_url;
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2043868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!favicon_bitmap_data[i].bitmap_data.get())
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
20472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!num_bitmaps_per_icon_url.count(icon_url))
20482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_bitmaps_per_icon_url[icon_url] = 1u;
20492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
20502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++num_bitmaps_per_icon_url[icon_url];
20512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
20522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
20542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
20572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != num_bitmaps_per_icon_url.end(); ++it) {
20582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->second > kMaxFaviconBitmapsPerIconURL)
20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::IsFaviconBitmapDataEqual(
20652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
20662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2067868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!new_bitmap_data.get())
20682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
20712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmap(bitmap_id,
20722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL,
20732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  &original_bitmap_data,
20742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL);
20752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_bitmap_data->Equals(original_bitmap_data);
20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconsFromDB(
20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
20816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
2082f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(favicon_bitmap_results);
20842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_bitmap_results->clear();
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2086b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Time the query.
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get FaviconIDs for |page_url| and one of |icon_types|.
20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &icon_mappings);
20960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i)
20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ids.push_back(icon_mappings[i].icon_id);
20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
21012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
21026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      desired_sizes, favicon_bitmap_results);
21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
21052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success && !favicon_bitmap_results->empty();
21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
21090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& candidate_favicon_ids,
21106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
2111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_bitmap_results->clear();
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_favicon_ids.empty())
21155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the FaviconID and the FaviconBitmapIDs which best match
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |desired_size_in_dip| and |desired_scale_factors|.
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Select bitmap results from multiple favicons once
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // content::FaviconStatus supports multiple icon URLs.
21210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID best_favicon_id = 0;
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapID> best_bitmap_ids;
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float highest_score = kSelectFaviconFramesInvalidScore;
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &bitmap_id_sizes);
21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build vector of gfx::Size from |bitmap_id_sizes|.
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<gfx::Size> sizes;
21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizes.push_back(bitmap_id_sizes[j].pixel_size);
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<size_t> candidate_bitmap_indices;
21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score = 0;
21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFaviconFrameIndices(sizes,
21376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                              desired_sizes,
21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &candidate_bitmap_indices,
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &score);
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (score > highest_score) {
21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      highest_score = score;
21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_favicon_id = candidate_favicon_ids[i],
21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_bitmap_ids.clear();
21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_t candidate_index = candidate_bitmap_indices[j];
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        best_bitmap_ids.push_back(
21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bitmap_id_sizes[candidate_index].bitmap_id);
21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Construct FaviconRawBitmapResults from |best_favicon_id| and
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |best_bitmap_ids|.
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
21550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       &icon_type)) {
21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time last_updated;
2163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult bitmap_result;
21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_url = icon_url;
21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_type = icon_type;
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &last_updated,
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.bitmap_data,
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.pixel_size)) {
21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.expired = (Time::Now() - last_updated) >
21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromDays(kFaviconRefetchDays);
21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bitmap_result.is_valid())
21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
21830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
21840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
2185b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find all the pages whose favicons we should set, we want to set it for
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the pages in the redirect chain if it redirected.
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirects;
21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirects);
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save page <-> favicon associations.
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (history::RedirectList::const_iterator i(redirects.begin());
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != redirects.end(); ++i) {
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPage(
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
22050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
22060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two icon types are considered 'equivalent' if one of the icon types is
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any favicons which are orphaned as a result of the removal of the
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon mappings.
22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> unmapped_icon_ids = icon_ids;
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
22270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID>::iterator icon_id_it = std::find(
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the icon mapping already exists, avoid removing it and adding it back.
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_id_it != unmapped_icon_ids.end()) {
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unmapped_icon_ids.erase(icon_id_it);
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((icon_type == favicon_base::TOUCH_ICON &&
22370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON) ||
22380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON &&
22390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_ICON) ||
22400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == m->icon_type)) {
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->DeleteIconMapping(m->mapping_id);
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removing the icon mapping may have orphaned the associated favicon so
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we must recheck it. This is not super fast, but this case will get
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered rarely, since normally a page will always map to the same
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // favicon IDs. It will mostly happen for favicons we import.
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!thumbnail_db_->HasMappingFor(m->icon_id))
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->DeleteFavicon(m->icon_id);
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappings_changed = true;
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed = true;
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetCachedRecentRedirects(
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirect_list) {
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *redirect_list = iter->second;
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The redirect chain should have the destination URL as the last item.
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirect_list->empty());
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirect_list->back() == page_url);
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No known redirects, construct mock redirect chain containing |page_url|.
22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirect_list->push_back(page_url);
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirect_list;
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirect_list);
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<FaviconChangedDetails> changed_details(new FaviconChangedDetails);
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirect_list.size(); ++i)
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.insert(redirect_list[i]);
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         changed_details.PassAs<HistoryDetails>());
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Commit() {
2290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that a commit may not actually have been scheduled if a caller
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly calls this instead of using ScheduleCommit. Likewise, we
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may reset the flag written by a pending commit. But this is OK! It
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will merely cause extra commits (which is kind of the idea). We
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could optimize more for this case (we may get two extra commits in
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some cases) but it hasn't been important yet.
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Somebody left a transaction open";
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleCommit() {
2314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get())
23155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduled_commit_ = new CommitLaterTask(this);
231790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CancelScheduledCommit() {
2324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get()) {
23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_->Cancel();
23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_ = NULL;
23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTaskImpl() {
2331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // db went away, release all the refs.
2333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    queued_history_db_tasks_.clear();
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any canceled tasks.
2338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (!queued_history_db_tasks_.empty()) {
2339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QueuedHistoryDBTask& task = queued_history_db_tasks_.front();
2340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!task.is_canceled()) {
2341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
2342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
2343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    queued_history_db_tasks_.pop_front();
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (queued_history_db_tasks_.empty())
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the first task.
2349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  QueuedHistoryDBTask task = queued_history_db_tasks_.front();
2350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_history_db_tasks_.pop_front();
2351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (task.RunOnDBThread(this, db_.get())) {
2352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // The task is done, notify the callback.
2353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    task.DoneRunOnMainThread();
23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // The task wants to run some more. Schedule it at the end of the current
2356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // tasks, and process it after an invoke later.
2357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    queued_history_db_tasks_.insert(queued_history_db_tasks_.end(), task);
235890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generic operations
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURLs(urls);
23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURL(const GURL& url) {
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURL(url);
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ExpireHistoryBetween(
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& restrict_urls,
23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time begin_time,
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time end_time) {
239158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!db_)
239258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
239458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
239558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      restrict_urls.empty()) {
239658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Special case deleting all history so it can be faster and to reduce the
239758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // possibility of an information leak.
239858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DeleteAllHistory();
239958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
240058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Clearing parts of history, have the expirer do the depend
240158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
240258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
240358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Force a commit, if the user is deleting something for privacy reasons,
240458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // we want to get it on disk ASAP.
240558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Commit();
24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin_time <= first_recorded_time_)
24095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
24102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
24112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistoryForTimes(
24132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<base::Time>& times,
24142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time, base::Time end_time) {
2415b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (times.empty() || !db_)
24162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
24172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.begin() >= begin_time)
24192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Min time is before begin time: "
24202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
24212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.rbegin() < end_time)
24222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Max time is after end time: "
24232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
24242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::QueryOptions options;
24262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.begin_time = begin_time;
24272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.end_time = end_time;
24282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
24292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryResults results;
243046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  QueryHistoryBasic(options, &results);
24312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1st pass: find URLs that are visited at one of |times|.
24332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<GURL> urls;
24342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
24352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (times.count(results[i].visit_time()) > 0)
24362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      urls.insert(results[i].url());
24372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
24382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (urls.empty())
24392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
24402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2nd pass: collect all visit times of those URLs.
24422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Time> times_to_expire;
24432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
24442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (urls.count(results[i].url()))
24452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.push_back(results[i].visit_time());
24462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
24472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put the times in reverse chronological order and remove
24492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // duplicates (for expirer_.ExpireHistoryForTimes()).
24502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::sort(times_to_expire.begin(), times_to_expire.end(),
24512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            std::greater<base::Time>());
24522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  times_to_expire.erase(
24532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::unique(times_to_expire.begin(), times_to_expire.end()),
24542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.end());
24552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expires by times and commit.
24572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!times_to_expire.empty());
24582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expirer_.ExpireHistoryForTimes(times_to_expire);
24592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Commit();
24602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(times_to_expire.back() >= first_recorded_time_);
24622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update |first_recorded_time_| if we expired it.
24632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (times_to_expire.back() == first_recorded_time_)
24642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
24652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistory(
24682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2469b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
24702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_first_recorded_time = false;
24712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
24732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         expire_list.begin(); it != expire_list.end(); ++it) {
24742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->begin_time < first_recorded_time_)
24772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        update_first_recorded_time = true;
24782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
24792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Commit();
24802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update |first_recorded_time_| if any deletion might have affected it.
24822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (update_first_recorded_time)
24832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_->GetStartDate(&first_recorded_time_);
24842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2488b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow url_row;
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(*i, &url_row))
24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // The URL isn't in the db; nothing to do.
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector visits;
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetVisitsForURL(url_row.id(), &visits);
24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visits.empty())
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
25057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
25067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scheduled_kill_db_ = true;
25077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Don't just do the close/delete here, as we are being called by |db| and
25087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that seems dangerous.
25097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // TODO(shess): Consider changing KillHistoryDatabase() to use
25107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // RazeAndClose().  Then it can be cleared immediately.
25117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
25127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        FROM_HERE,
25137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::Bind(&HistoryBackend::KillHistoryDatabase, this));
25147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
25157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
25167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
25175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::KillHistoryDatabase() {
25187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scheduled_kill_db_ = false;
2519b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
25205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rollback transaction because Raze() cannot be called from within a
25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RollbackTransaction();
25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = db_->Raze();
25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
25315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
25325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expirer keeps tabs on the active databases. Tell it about the
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // databases which will be closed.
253546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.SetDatabases(NULL, NULL);
25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTask(
2543116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<HistoryDBTask> task,
2544116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
2545116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
2546116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool scheduled = !queued_history_db_tasks_.empty();
2547116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_history_db_tasks_.insert(
2548116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      queued_history_db_tasks_.end(),
2549116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      QueuedHistoryDBTask(task, origin_loop, is_canceled));
2550116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!scheduled)
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessDBTaskImpl();
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::BroadcastNotifications(
25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
2556a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<HistoryDetails> details) {
25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2558b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // HistoryService -> HistoryBackend::Closing().
2559b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
2560a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    delegate_->BroadcastNotifications(type, details.Pass());
25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid HistoryBackend::NotifySyncURLsModified(URLRows* rows) {
25640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (typed_url_syncable_service_.get())
25650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    typed_url_syncable_service_->OnUrlsModified(rows);
25660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
25670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2568b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
256946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                           bool expired,
2570b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           URLRows* rows) {
2571b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
257246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsDeleted(all_history, expired, rows);
2573b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
2574b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
25755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deleting --------------------------------------------------------------------
25765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllHistory() {
25785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our approach to deleting all history is:
25795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  1. Copy the bookmarks and their dependencies to new tables with temporary
25805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     names.
25815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  2. Delete the original tables. Since tables can not share pages, we know
25825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     that any data we don't want to keep is now in an unused page.
25835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  3. Renaming the temporary tables to match the original.
25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  4. Vacuuming the database to delete the unused pages.
25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we are likely to have very few bookmarks and their dependencies
25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compared to all history, this is also much faster than just deleting from
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original tables directly.
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bookmarked URLs.
259146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<URLAndTitle> starred_urls;
259246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  HistoryClient* history_client = GetHistoryClient();
259346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (history_client)
259446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    history_client->GetBookmarks(&starred_urls);
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRows kept_urls;
25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < starred_urls.size(); i++) {
25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(starred_urls[i].url, &row))
26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear the last visit time so when we write these rows they are "clean."
26035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_last_visit(Time());
26045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_visit_count(0);
26055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_typed_count(0);
26065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kept_urls.push_back(row);
26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear thumbnail and favicon history. The favicons for the given URLs will
26105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be kept.
26113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClearAllThumbnailHistory(kept_urls)) {
26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Thumbnail history could not be cleared";
26135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We continue in this error case. If the user wants to delete their
26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // history, we should delete as much as we can.
26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
261758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
261858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Therefore, we clear the list afterwards to make sure nobody uses this
261958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // invalid data.
26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllMainHistory(kept_urls))
26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Main history could not be cleared";
26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kept_urls.clear();
26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Send out the notification that history is cleared. The in-memory database
26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will pick this up and clear itself.
2628a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails);
26295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->all_history = true;
2630b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NotifySyncURLsDeleted(true, false, NULL);
2631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
2632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         details.PassAs<HistoryDetails>());
26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2636b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we have no reference to the thumbnail database, maybe there was an
26385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error opening it. In this case, we just try to blow it away to try to
26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fix the error if it exists. This may fail, in which case either the
26405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file doesn't exist or there's no more we can do.
26413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sql::Connection::Delete(GetFaviconsFileName());
26423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
26433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Older version of the database.
2644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(GetThumbnailFileName());
26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Urls to retain mappings for.
26493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<GURL> urls_to_keep;
26503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin();
26513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != kept_urls.end(); ++i) {
26523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    urls_to_keep.push_back(i->url());
26533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
26545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Isolate from any long-running transaction.
26563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
26573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): If this fails, perhaps the database should be razed
26603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // or deleted.
26613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
26623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->RollbackTransaction();
26633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
26643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
26655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
26695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avaliable in HistoryBackend.
26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->ClearAndroidURLRows();
26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to remove all the pages associated with the dropped tables. There
26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must be no transaction open on the table when we do this. We assume that
26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our long-running transaction is open, so we complete it and start it again.
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thumbnail_db_->transaction_nesting() == 1);
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->Vacuum();
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the duplicate URL table. We will copy the kept URLs into this.
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CreateTemporaryURLTable())
26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
268858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Insert the URLs into the temporary table.
26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
26905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
269158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    db_->AddTemporaryURL(*i);
26925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the original URL table with the temporary one.
26955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CommitTemporaryURLTable())
26965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
26975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the old tables and recreate them empty.
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RecreateAllTablesButURL();
27005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to reclaim the space from the dropped tables. This must be done
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when there is no transaction open, and we assume that our long-running
27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction is currently open.
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->Vacuum();
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
271246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)HistoryClient* HistoryBackend::GetHistoryClient() {
271346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (history_client_)
271446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    history_client_->BlockUntilBookmarksLoaded();
271546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return history_client_;
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BriefVisitInfo info;
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.url_id = visit.url_id;
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.time = visit.visit_time;
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.transition = visit.transition;
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a delegate yet during setup or shutdown, we will drop
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these notifications.
2725b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
27265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->NotifyVisitDBObserversOnAddVisit(info);
27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2729eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
2730eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::PopulateMostVisitedURLMap() {
2731eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MostVisitedURLList most_visited_urls;
2732116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  QueryMostVisitedURLs(
2733116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kPageVisitStatsMaxTopSites, kSegmentDataRetention, &most_visited_urls);
2734eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2735eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2736eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2737eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    most_visited_urls_map_[most_visited_urls[i].url] = i;
2738eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2739eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2740eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2741eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2742eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2743eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2744eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rank = kPageVisitStatsMaxTopSites;
2745eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2746eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it != most_visited_urls_map_.end())
2747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    rank = (*it).second;
2748eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2749eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            rank, kPageVisitStatsMaxTopSites + 1);
2750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2752eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
27535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
2754