history_backend.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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"
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/common/importer/imported_favicon_usage.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "components/favicon_base/select_favicon_frames.h"
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/history/core/browser/history_client.h"
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/history/core/browser/keyword_search_term.h"
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/history/core/browser/page_usage_data.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/error_delegate_util.h"
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)/* The HistoryBackend consists of two components:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ExpireHistoryBackend (manages deleting things older than 3 months)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid RunUnlessCanceled(
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::Closure& closure,
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!is_canceled.Run())
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    closure.Run();
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(OS_ANDROID)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we keep segment data for in days. Currently 3 months.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This value needs to be greater or equal to
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dependency between MostVisitedModel and the history backend.
8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kSegmentDataRetention = 90;
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kCommitIntervalSeconds = 10;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time before we re-fetch the favicon.
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kFaviconRefetchDays = 7;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleting some.
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kMaxRedirectCount = 32;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// and is deleted.
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const int kExpireDaysThreshold = 90;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The maximum number of top sites to track when recording top page visit stats.
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const size_t kPageVisitStatsMaxTopSites = 50;
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts from PageUsageData to MostVisitedURL. |redirects| is a
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const RedirectList& redirects) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURL mv;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.url = page_data.GetURL();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.title = page_data.GetTitle();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (redirects.empty()) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirects must contain at least the target url.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects.push_back(mv.url);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects = redirects;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last url must be the target url.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mv.redirects.push_back(mv.url);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mv;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they are batched together. The important thing about this class is that
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be one of these commits still pending and holding a reference.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// task will still run (if we ever get to processing the event before
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown), but it will not do anything.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be assigned to a RunnableMethod.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in ExpireHistoryBackend).
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommitLaterTask(HistoryBackend* history_backend)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : history_backend_(history_backend) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The backend will call this function if it is being destroyed so that we
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release our reference.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_backend_ = NULL;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCommit() {
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (history_backend_.get())
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_backend_->Commit();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommitLaterTask() {}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
170116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQueuedHistoryDBTask::QueuedHistoryDBTask(
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<HistoryDBTask> task,
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled)
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : task_(task.Pass()), origin_loop_(origin_loop), is_canceled_(is_canceled) {
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(task_);
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(origin_loop_);
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!is_canceled_.is_null());
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
180116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQueuedHistoryDBTask::~QueuedHistoryDBTask() {
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Ensure that |task_| is destroyed on its origin thread.
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  origin_loop_->PostTask(
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&base::DeletePointer<HistoryDBTask>,
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Unretained(task_.release())));
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool QueuedHistoryDBTask::is_canceled() {
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return is_canceled_.Run();
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool QueuedHistoryDBTask::Run(HistoryBackend* backend,
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        HistoryDatabase* db) {
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return task_->RunOnDBThread(backend, db);
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void QueuedHistoryDBTask::DoneRun() {
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  origin_loop_->PostTask(
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&RunUnlessCanceled,
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Bind(&HistoryDBTask::DoneRunOnMainThread,
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            base::Unretained(task_.get())),
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 is_canceled_));
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HistoryBackend --------------------------------------------------------------
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Delegate* delegate,
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               HistoryClient* history_client)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_dir_(history_dir),
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      scheduled_kill_db_(false),
21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      expirer_(this, history_client),
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recent_redirects_(kMaxRedirectCount),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_destroy_message_loop_(NULL),
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_(false),
21846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      history_client_(history_client) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryBackend::~HistoryBackend() {
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  STLDeleteContainerPointers(queued_history_db_tasks_.begin(),
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             queued_history_db_tasks_.end());
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_history_db_tasks_.clear();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sql::Connection::Delete(GetAndroidCacheFileName());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Init(const std::string& languages, bool force_fail) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force_fail)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitImpl(languages);
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delegate_->DBLoaded();
250b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
251ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  memory_pressure_listener_.reset(new base::MemoryPressureListener(
252ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PopulateMostVisitedURLMap();
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const base::Closure& task) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null())
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_task_ = task;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Closing() {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any scheduled commit will have a reference to us, we must make it
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release that reference before we can be destroyed.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release our reference to the delegate, this reference will be keeping the
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // history service alive.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void HistoryBackend::ClearCachedDataForContextID(ContextID context_id) {
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  tracker_.ClearCachedDataForContextID(context_id);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetThumbnailFileName() const {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kThumbnailsFilename);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetFaviconsFileName() const {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kFaviconsFilename);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetArchivedFileName() const {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kArchivedHistoryFilename);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kAndroidCacheFilename);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is used to detect referrer loops.  Should not happen, but can
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the database is corrupt.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = from_visit;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (visit_id) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitRow row;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForVisit(visit_id, &row))
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row.segment_id)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return row.segment_id;  // Found a visit in this change with a segment.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the referrer of this visit, if any.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_id = row.referring_visit;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(visit_id) != visit_set.end()) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in referer chain, giving up";
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(visit_id);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::UpdateSegments(
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID from_visit,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID visit_id,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition_type,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time ts) {
328b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only consider main frames.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!content::PageTransitionIsMainFrame(transition_type))
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SegmentID segment_id = 0;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition t =
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition_type);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are we at the beginning of a new segment?
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that navigating to an existing entry (with back/forward) reuses the
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same transition type.  We are not adding it as a new segment in that case
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because if this was the target of a redirect, we might end up with
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2 entries for the same final URL. Ex: User types google.net, gets
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirected to google.com. A segment is created for google.net. On
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // google.com users navigates through a link, then press back. That last
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation is for the entry google.com transition typed. We end up adding
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a segment for that one as well. So we end up with google.net and google.com
34858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // in the segment table, showing as 2 entries in the NTP.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note also that we should still be updating the visit count for that segment
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which we are not doing now. It should be addressed when
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://crbug.com/96860 is fixed.
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((t == content::PAGE_TRANSITION_TYPED ||
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If so, create or get the segment.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string segment_name = db_->ComputeSegmentName(url);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    segment_id = db_->GetSegmentNamed(segment_name);
362116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!segment_id) {
363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      segment_id = db_->CreateSegment(url_id, segment_name);
364116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!segment_id) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: if we update an existing segment, we update the url used to
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // represent that segment in order to minimize stale most visited
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // images.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: it is possible there is no segment ID set for this visit chain.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TYPED. (For example GENERATED). In this case this visit doesn't count
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // toward any segment.
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    segment_id = GetLastSegmentID(from_visit);
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!segment_id)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the segment in the visit.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->SetSegmentID(visit_id, segment_id)) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, increase the counter for that segment / day.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return segment_id;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
398f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void HistoryBackend::UpdateWithPageEndTime(ContextID context_id,
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int32 page_id,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const GURL& url,
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Time end_ts) {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
403f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  VisitID visit_id = tracker_.GetLastVisit(context_id, page_id, url);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisitDuration(visit_id, end_ts);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
408b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the starting visit_time for visit_id.
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_row;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetRowForVisit(visit_id, &visit_row)) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should never have a negative duration time even when time is skewed.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_row.visit_duration = end_ts > visit_row.visit_time ?
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateVisitRow(visit_row);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
422b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
427f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      request.context_id, request.page_id, request.referrer));
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID from_visit_id = last_ids.second;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a redirect chain is given, we expect the last item in that chain to be
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the final URL.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request.redirects.empty() ||
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         request.redirects.back() == request.url);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is adding older history, we need to make sure our times
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are correct.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request.time < first_recorded_time_)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = request.time;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition request_transition = request.transition;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition stripped_transition =
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransitionStripQualifier(request_transition);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_generated =
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is navigating to a not-previously-typed intranet hostname,
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the transition to TYPED so that the omnibox will learn that this is
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a known host.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_redirects = request.redirects.size() > 1;
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (content::PageTransitionIsMainFrame(request_transition) &&
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url(has_redirects ?
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request.redirects[0] : request.url);
456010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (origin_url.SchemeIs(url::kHttpScheme) ||
457010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        origin_url.SchemeIs(url::kHttpsScheme) ||
458cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        origin_url.SchemeIs(url::kFtpScheme)) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string host(origin_url.host());
460a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      size_t registry_length =
461a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          net::registry_controlled_domains::GetRegistryLength(
462a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              host,
463a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
464a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
465a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (registry_length == 0 && !db_->IsTypedHost(host)) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stripped_transition = content::PAGE_TRANSITION_TYPED;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition =
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::PageTransitionFromInt(
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                stripped_transition |
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                content::PageTransitionGetQualifier(request_transition));
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_redirects) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The single entry is both a chain start and end.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition t = content::PageTransitionFromInt(
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition |
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START |
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_END);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect case (one element means just the page itself).
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_ids = AddPageVisit(request.url, request.time,
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            last_ids.second, t, request.visit_source);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the segment for this visit. KEYWORD_GENERATED visits should not
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result in changing most visited, so we don't update segments (most
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // visited db).
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_keyword_generated) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     request.time);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the referrer's duration.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateVisitDuration(from_visit_id, request.time);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirect case. Add the redirect chain.
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition redirect_info =
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects = request.redirects;
503f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (redirects[0].SchemeIs(url::kAboutScheme)) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the redirect source + referrer is "about" we skip it. This
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // happens when a page opens a new frame/window to about:blank and then
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // script sets the URL to somewhere else (used to hide the referrer). It
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would be nice to keep all these redirects properly but we don't ever
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // see the initial about:blank load, so we don't know where the
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // subsequent client redirect came from.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this case, we just don't bother hooking up the source of the
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects, so we remove it.
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirects.erase(redirects.begin());
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The first entry in the redirect chain initiated a client redirect.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't add this to the database since the referrer is already
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // there, so we skip over it but change the transition type of the first
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transition to client redirect.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The referrer is invalid when restoring a session that features an
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // https tab that redirects to a different host or to http. In this
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case we don't need to reconnect the new redirect with the existing
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // chain.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (request.referrer.is_valid()) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(request.referrer == redirects[0]);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        redirects.erase(redirects.begin());
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the navigation entry for this visit has replaced that for the
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // first visit, remove the CHAIN_END marker from the first visit. This
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can be called a lot, for example, the page cycler, and most of the
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // time we won't have changed anything.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisitRow visit_row;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (request.did_replace_entry &&
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db_->GetRowForVisit(last_ids.second, &visit_row) &&
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          visit_row.transition = content::PageTransitionFromInt(
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->UpdateVisitRow(visit_row);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t redirect_index = 0; redirect_index < redirects.size();
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         redirect_index++) {
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransition t =
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::PageTransitionFromInt(stripped_transition | redirect_info);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If this is the last transition, add a CHAIN_END marker
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (redirect_index == (redirects.size() - 1)) {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t = content::PageTransitionFromInt(
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            t | content::PAGE_TRANSITION_CHAIN_END);
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Record all redirect visits with the same timestamp. We don't display
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them anyway, and if we ever decide to, we can reconstruct their order
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the redirect chain.
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_ids = AddPageVisit(redirects[redirect_index],
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              request.time, last_ids.second,
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              t, request.visit_source);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (t & content::PAGE_TRANSITION_CHAIN_START) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the segment for this visit.
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateSegments(redirects[redirect_index],
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       from_visit_id, last_ids.second, t, request.time);
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the visit_details for this visit.
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateVisitDuration(from_visit_id, request.time);
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Subsequent transitions in the redirect list must all be server
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects.
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last, save this redirect chain for later so we can set titles & favicons
576bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // on the redirected pages properly.
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recent_redirects_.Put(request.url, redirects);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the last visit to the tracker so we can get outgoing transitions.
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation anyway, so last_visit_id is always zero for them.  But adding
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them here confuses main frame history, so we skip them for now.
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
590f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    tracker_.AddVisit(request.context_id, request.page_id, request.url,
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      last_ids.second);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::InitImpl(const std::string& languages) {
598b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!db_) << "Initializing HistoryBackend twice";
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the rare case where the db fails to initialize a dialog may get shown
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the blocks the caller, yet allows other messages through. For this reason
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only set db_ to the created database if creation is successful. That
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way other methods won't do anything as db_ is still NULL.
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
606bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Compute the file names.
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
6083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::FilePath thumbnail_name = GetFaviconsFileName();
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath archived_name = GetArchivedFileName();
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
611bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete the old index database files which are no longer used.
612bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DeleteFTSIndexDatabases();
613bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // History database.
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new HistoryDatabase());
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Unretained to avoid a ref loop with db_.
6187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  db_->set_error_callback(
6197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Bind(&HistoryBackend::DatabaseErrorCallback,
6207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                 base::Unretained(this)));
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  sql::InitStatus status = db_->Init(history_name);
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_OK:
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_FAILURE: {
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A NULL db_ will cause all calls on this object to notice this error
6287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // and to not continue. If the error callback scheduled killing the
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database, the task it posted has not executed yet. Try killing the
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database now before we close it.
6317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      bool kill_db = scheduled_kill_db_;
6327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (kill_db)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        KillHistoryDatabase();
6347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
635a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->NotifyProfileError(status);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the in-memory database and send it back to the history service on the
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // main thread.
645a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  {
646a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<InMemoryHistoryBackend> mem_backend(new InMemoryHistoryBackend);
647116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (mem_backend->Init(history_name))
648a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->SetInMemoryBackend(mem_backend.Pass());
649a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Thumbnail database.
6533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): "thumbnail database" these days only stores
6543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // favicons.  Thumbnails are stored in "top sites".  Consider
6553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // renaming "thumbnail" references to "favicons" or something of the
6563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // sort.
657116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  thumbnail_db_.reset(new ThumbnailDatabase(history_client_));
6584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unlike the main database, we don't error out when the database is too
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new because this error is much less severe. Generally, this shouldn't
66158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // happen since the thumbnail and main database versions should be in sync.
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We'll just continue without thumbnails & favicons in this case or any
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other error.
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the thumbnail database.";
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Nuke any files corresponding to the legacy Archived History Database, which
66946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // previously retained expired (> 3 months old) history entries, but, in the
67046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // end, was not used for much, and consequently has been removed as of M37.
67146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(engedy): Remove this code after the end of 2014.
67246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  sql::Connection::Delete(archived_name);
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Generate the history and thumbnail database metrics only after performing
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any migration work.
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::RandInt(1, 100) == 50) {
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only do this computation sometimes since it can be expensive.
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->ComputeDatabaseMetrics(history_name);
6792385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (thumbnail_db_)
6802385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      thumbnail_db_->ComputeDatabaseMetrics();
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
68346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.SetDatabases(db_.get(), thumbnail_db_.get());
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the long-running transaction.
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
687b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the first item in our database.
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start expiring old stuff.
69446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.StartExpiringOldStuff(TimeDelta::FromDays(kExpireDaysThreshold));
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
697b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
69846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    android_provider_backend_.reset(
69946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        new AndroidProviderBackend(GetAndroidCacheFileName(),
70046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   db_.get(),
70146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   thumbnail_db_.get(),
70246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   history_client_,
70346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   delegate_.get()));
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HISTOGRAM_TIMES("History.InitTime",
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  TimeTicks::Now() - beginning_time);
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
711ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid HistoryBackend::OnMemoryPressure(
712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
713ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool trim_aggressively = memory_pressure_level ==
714ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
715ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (db_)
716ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    db_->TrimMemory(trim_aggressively);
717ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (thumbnail_db_)
718ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    thumbnail_db_->TrimMemory(trim_aggressively);
719ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
720ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloseAllDatabases() {
722b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the long-running transaction.
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->CommitTransaction();
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset();
72658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Forget the first recorded time since the database is closed.
72758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    first_recorded_time_ = base::Time();
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
729b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time time,
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID referring_visit,
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitSource visit_source) {
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Top-level frame navigations are visible, everything else is hidden
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool new_hidden = !content::PageTransitionIsMainFrame(transition);
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This code must stay in sync with
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExpireHistoryBackend::ExpireURLsForVisits().
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // typed, which would eliminate the need for this code.
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int typed_increment = 0;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition transition_type =
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((transition_type == content::PAGE_TRANSITION_TYPED &&
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !content::PageTransitionIsRedirect(transition)) ||
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typed_increment = 1;
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
756eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
757eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Only count the page visit if it came from user browsing and only count it
758eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // once when cycling through a redirect chain.
759eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (visit_source == SOURCE_BROWSED &&
760eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
761eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordTopPageVisitStats(url);
762eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
763eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
764eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if this URL is already in the DB.
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update of an existing row.
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::PageTransitionStripQualifier(transition) !=
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_RELOAD)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_visit_count(url_info.visit_count() + 1);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (typed_increment)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_typed_count(url_info.typed_count() + typed_increment);
775c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (url_info.last_visit() < time)
776c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_info.set_last_visit(time);
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only allow un-hiding of pages, never hiding.
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_hidden)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_hidden(false);
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateURLRow(url_id, url_info);
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Addition of a new row.
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_visit_count(1);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_typed_count(typed_increment);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_last_visit(time);
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_hidden(new_hidden);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_id = db_->AddURL(url_info);
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Adding URL failed.";
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::make_pair(0, 0);
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.id_ = url_id;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the visit with the time to the database.
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyVisitObservers(visit_info);
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_info.visit_time < first_recorded_time_)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = visit_info.visit_time;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification of the visit.
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id) {
808b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
809b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
810b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
811a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<URLVisitedDetails> details(new URLVisitedDetails);
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->transition = transition;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->row = url_info;
814cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    details->visit_time = time;
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
817116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // QueryRedirectsTo(url, &details->redirects);
818a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED,
819a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
830b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // As of M37, we no longer maintain an archived database, ignore old visits.
83846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit()))
83946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
84246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    URLID url_id = db_->GetRowForURL(i->url(), &existing_url);
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
84546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      url_id = db_->AddURL(*i);
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
851f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      modified->changed_urls.push_back(*i);
852f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      modified->changed_urls.back().set_id(url_id);  // i->id_ is likely 0.
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          content::PageTransitionFromInt(
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_LINK |
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_START |
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_END), 0);
86346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!db_->AddVisit(&visit_info, visit_source)) {
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (typed_url_syncable_service_.get())
875b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
876b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
883a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         modified.PassAs<HistoryDetails>());
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
88946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return time < expirer_.GetCurrentExpirationTime();
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
892a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url,
893a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  const base::string16& title) {
894b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
930b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
931b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
933a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
939a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               const base::string16& title) {
940b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_info.set_title(base::UTF8ToUTF16(url.spec()));
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
96490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
966b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
981b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
987b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int max_visits,
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               VisitVector* visits) {
995b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1000116680a4aac90f2aa7413d9095a592090648e557Ben Murdochsize_t HistoryBackend::UpdateURLs(const history::URLRows& urls) {
1001116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
1002116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return 0;
1003116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1004116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
1005116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (history::URLRows::const_iterator it = urls.begin(); it != urls.end();
1006116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++it) {
1007116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(it->id());
1008116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (db_->UpdateURLRow(it->id(), *it))
1009116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      details->changed_urls.push_back(*it);
1010116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1011116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1012116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Broadcast notifications for any URLs that have actually been changed. This
1013116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // will update the in-memory database and the InMemoryURLIndex.
1014116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t num_updated_records = details->changed_urls.size();
1015116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (num_updated_records) {
1016116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (typed_url_syncable_service_)
1017116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
1018116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1019116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           details.PassAs<HistoryDetails>());
1020116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ScheduleCommit();
1021116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1022116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return num_updated_records;
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::AddVisits(const GURL& url,
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<VisitInfo>& visits,
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               VisitSource visit_source) {
1028b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         visit != visits.end(); ++visit) {
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!AddPageVisit(
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              url, visit->first, 0, visit->second, visit_source).first) {
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1043b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.ExpireVisits(visits);
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VisitSourceMap* sources) {
1053b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetVisitsSource(visits, sources);
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1061b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetRowForURL(url, url_row) != 0;
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1066116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryURL(const GURL& url,
1067116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                              bool want_visits,
1068116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                              QueryURLResult* result) {
1069116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(result);
1070116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->success = db_ && db_->GetRowForURL(url, &result->row);
1071f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Optionally query the visits.
1072116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (result->success && want_visits)
1073116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    db_->GetVisitsForURL(result->row.id(), &result->visits);
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1076b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1077b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return typed_url_syncable_service_.get();
1078b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1079b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keyword visits --------------------------------------------------------------
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
1083116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 KeywordID keyword_id,
1084a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                 const base::string16& term) {
1085b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the ID for this URL.
10890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  URLRow row;
10900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!db_->GetRowForURL(url, &row)) {
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a small possibility the url was deleted before the keyword
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was added. Ignore the request.
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  db_->SetKeywordSearchTermsForURL(row.id(), keyword_id, term);
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(
10990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      scoped_ptr<HistoryDetails>(
11010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          new KeywordSearchUpdatedDetails(row, keyword_id, term)));
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
1106b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->DeleteAllSearchTermsForKeyword(keyword_id);
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void HistoryBackend::DeleteKeywordSearchTermForURL(const GURL& url) {
11140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!db_)
11150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, NULL);
11180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!url_id)
11190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  db_->DeleteKeywordSearchTermForURL(url_id);
11210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  BroadcastNotifications(
11230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
11240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_ptr<HistoryDetails>(new KeywordSearchDeletedDetails(url_id)));
11250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScheduleCommit();
11260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
11270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1128116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
11295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  const base::string16& term) {
11305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_)
11315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
11325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<KeywordSearchTermRow> rows;
11345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_->GetKeywordSearchTermRows(term, &rows)) {
11355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<GURL> items_to_delete;
11365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLRow row;
11375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (std::vector<KeywordSearchTermRow>::iterator it = rows.begin();
11385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it != rows.end(); ++it) {
11395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if ((it->keyword_id == keyword_id) && db_->GetURLRow(it->url_id, &row))
11405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        items_to_delete.push_back(row.url());
11415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
11425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DeleteURLs(items_to_delete);
11435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
11445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
11455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Downloads -------------------------------------------------------------------
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)uint32 HistoryBackend::GetNextDownloadId() {
1149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return db_ ? db_->GetNextDownloadId() : content::DownloadItem::kInvalidId;
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get all the download entries from the database.
11532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QueryDownloads(rows);
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update a particular download entry.
11592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->UpdateDownload(data);
11632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HistoryBackend::CreateDownload(const history::DownloadRow& history_info) {
1167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
1168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
1169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool success = db_->CreateDownload(history_info);
11702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
1171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return success;
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1175b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_before = db_->CountDownloads();
11782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks started_removing = base::TimeTicks::Now();
11792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HistoryBackend uses a long-running Transaction that is committed
11802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // periodically, so this loop doesn't actually hit the disk too hard.
11817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::set<uint32>::const_iterator it = ids.begin();
11827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       it != ids.end(); ++it) {
11832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->RemoveDownload(*it);
11842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScheduleCommit();
11862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks finished_removing = base::TimeTicks::Now();
11877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_after = db_->CountDownloads();
11887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
11897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_LE(downloads_count_after, downloads_count_before);
11907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (downloads_count_after > downloads_count_before)
11917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
11927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
11937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
11947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        num_downloads_deleted);
11957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeDelta micros = (1000 * (finished_removing - started_removing));
11967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
11977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (num_downloads_deleted > 0) {
11987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
11997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        (1000 * micros) / num_downloads_deleted);
12002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GE(ids.size(), num_downloads_deleted);
12027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (ids.size() < num_downloads_deleted)
12037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
12057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        ids.size() - num_downloads_deleted);
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1208116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryHistory(const base::string16& text_query,
1209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  const QueryOptions& options,
1210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  QueryResults* query_results) {
1211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(query_results);
1212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeTicks beginning_time = base::TimeTicks::Now();
1213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (text_query.empty()) {
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Basic history query for the main database.
1216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      QueryHistoryBasic(options, query_results);
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Text history query.
1219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      QueryHistoryText(text_query, options, query_results);
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.QueryHistory",
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic time-based querying of history.
122746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void HistoryBackend::QueryHistoryBasic(const QueryOptions& options,
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QueryResults* result) {
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First get all visits.
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
123146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool has_more_results = db_->GetVisibleVisitsInRange(options, &visits);
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add them and the URL rows to the results.
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); i++) {
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VisitRow visit = visits[i];
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add a result row for this visit, get the URL info from the DB.
124046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!db_->GetURLRow(visit.url_id, &url_result)) {
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to get id " << visit.url_id
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " from history.urls.";
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // DB out of sync and URL doesn't exist, try to recover.
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid()) {
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Got invalid URL from history.urls with id "
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << visit.url_id << ":  "
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << url_result.url().possibly_invalid_spec();
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(visit.visit_time);
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Set whether the visit was blocked for a managed user by looking at the
1256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // transition type.
1257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url_result.set_blocked_visit(
1258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't set any of the query-specific parts of the URLResult, since
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // snippets and stuff don't apply to basic querying.
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_more_results && options.begin_time <= first_recorded_time_)
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Text-based querying of history.
127046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void HistoryBackend::QueryHistoryText(const base::string16& text_query,
1271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const QueryOptions& options,
1272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      QueryResults* result) {
1273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  URLRows text_matches;
127446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  db_->GetTextMatches(text_query, &text_matches);
1275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<URLResult> matching_visits;
1277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VisitVector visits;    // Declare outside loop to prevent re-construction.
1278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < text_matches.size(); i++) {
1279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const URLRow& text_match = text_matches[i];
1280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Get all visits for given URL match.
128146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    db_->GetVisibleVisitsForURL(text_match.id(), options, &visits);
1282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < visits.size(); j++) {
1283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      URLResult url_result(text_match);
1284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_result.set_visit_time(visits[j].visit_time);
1285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      matching_visits.push_back(url_result);
1286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::sort(matching_visits.begin(), matching_visits.end(),
1290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            URLResult::CompareVisitTime);
1291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t max_results = options.max_count == 0 ?
1293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (std::vector<URLResult>::iterator it = matching_visits.begin();
1295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != matching_visits.end() && result->size() < max_results; ++it) {
1296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->AppendURLBySwapping(&(*it));
1297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (matching_visits.size() == result->size() &&
1300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      options.begin_time <= first_recorded_time_)
1301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->set_reached_beginning(true);
1302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1304116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryRedirectsFrom(const GURL& from_url,
1305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        RedirectList* redirects) {
1306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  redirects->clear();
1307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
1311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
1312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!cur_visit)
1313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;  // No visits for URL.
1314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GetRedirectsFromSpecificVisit(cur_visit, redirects);
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1318116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryRedirectsTo(const GURL& to_url,
1319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      RedirectList* redirects) {
1320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  redirects->clear();
1321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
1325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
1326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!cur_visit)
1327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;  // No visits for URL.
1328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GetRedirectsToSpecificVisit(cur_visit, redirects);
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetVisibleVisitCountToHost(
1333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const GURL& url,
1334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    VisibleVisitCountToHostResult* result) {
1335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->count = 0;
1336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->success = db_.get() &&
1337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                    db_->GetVisibleVisitCountToHost(
1338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        url, &result->count, &result->first_visit);
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1341116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryMostVisitedURLs(int result_count,
1342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          int days_back,
1343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          MostVisitedURLList* result) {
1344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!db_)
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
1348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  db_->QuerySegmentUsage(
1349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Time::Now() - base::TimeDelta::FromDays(days_back),
1350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      result_count,
1351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &data.get());
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
1354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PageUsageData* current_data = data[i];
1355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RedirectList redirects;
1356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QueryRedirectsFrom(current_data->GetURL(), &redirects);
1357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
1358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result->push_back(url);
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1362116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::QueryFilteredURLs(int result_count,
1363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       const history::VisitFilter& filter,
1364116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       bool extended_info,
1365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       history::FilteredURLList* result) {
1366116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(result);
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time request_start = base::Time::Now();
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->clear();
1370b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, double> score_map;
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); ++i) {
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(georgey): experiment with visit_segment database granularity (it is
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently 24 hours) to use it directly instead of using visits database,
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is considerably slower.
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.reserve(score_map.size());
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<URLID, double>::iterator it = score_map.begin();
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != score_map.end(); ++it) {
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* pud = new PageUsageData(it->first);
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pud->SetScore(it->second);
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.push_back(pud);
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit to the top |result_count| results.
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
13972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_count && implicit_cast<int>(data.size()) > result_count)
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.resize(result_count);
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow info;
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetURLRow(data[i]->GetID(), &info)) {
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetURL(info.url());
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetTitle(info.title());
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilteredURL url(*current_data);
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extended_info) {
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitVector visits;
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisitsForURL(current_data->GetID(), &visits);
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits.size() > 0) {
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url.extended_info.total_visits = visits.size();
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < visits.size(); ++i) {
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url.extended_info.duration_opened +=
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visits[i].visit_duration.InSeconds();
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (visits[i].visit_time > url.extended_info.last_visit_time) {
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url.extended_info.last_visit_time = visits[i].visit_time;
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(macourteau): implement the url.extended_info.visits stat.
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result->push_back(url);
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta_time = std::max(1, std::min(999,
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATIC_HISTOGRAM_POINTER_BLOCK(
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NewTabPage.SuggestedSitesLoadTime",
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Add(delta_time),
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsFromSpecificVisit(
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit, history::RedirectList* redirects) {
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow any redirects from the given visit and add them to the list.
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It *should* be impossible to get a circular chain here, but we check
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just in case to avoid infinite loops.
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsToSpecificVisit(
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit,
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow redirects going to cur_visit. These are added to |redirects| in
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the order they are found. If a redirect chain looks like A -> B -> C and
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |cur_visit| = C, redirects will be {B, A} in that order.
1463b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1479116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HistoryBackend::ScheduleAutocomplete(const base::Callback<
1480116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    void(history::HistoryBackend*, history::URLDatabase*)>& callback) {
1481116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  callback.Run(this, db_.get());
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1484bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid HistoryBackend::DeleteFTSIndexDatabases() {
1485bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Find files on disk matching the text databases file pattern so we can
1486bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // quickly test for and delete them.
1487bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath::StringType filepattern =
1488bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FILE_PATH_LITERAL("History Index *");
1489bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FileEnumerator enumerator(
1490bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      history_dir_, false, base::FileEnumerator::FILES, filepattern);
1491bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  int num_databases_deleted = 0;
1492bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath current_file;
1493bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  while (!(current_file = enumerator.Next()).empty()) {
1494bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (sql::Connection::Delete(current_file))
1495bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      num_databases_deleted++;
1496bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1497bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1498bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                       num_databases_deleted);
1499bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
1500bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFavicons(
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
15046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1505f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
15066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types, desired_sizes,
15072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void HistoryBackend::GetLargestFaviconForURL(
15110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const GURL& page_url,
15120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<int>& icon_types,
15130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int minimum_size_in_pixels,
1514f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult* favicon_bitmap_result) {
15158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(favicon_bitmap_result);
15168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
15188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
15218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
15238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
15248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      icon_mappings.empty())
15258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int required_icon_types = 0;
15288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator i = icon_types.begin();
15298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_types.end(); ++i) {
15308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    required_icon_types |= *i;
15318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find the largest bitmap for each IconType placing in
15348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // |largest_favicon_bitmaps|.
15350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::map<favicon_base::IconType, FaviconBitmap> largest_favicon_bitmaps;
15368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
15378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_mappings.end(); ++i) {
15388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!(i->icon_type & required_icon_types))
15398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      continue;
15408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
15418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
15428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
15438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (std::vector<FaviconBitmapIDSize>::const_iterator j =
15448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)             bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
15458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (largest.bitmap_id == 0 ||
15468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest.pixel_size.width() < j->pixel_size.width() &&
15478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           largest.pixel_size.height() < j->pixel_size.height())) {
15488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.icon_id = i->icon_id;
15498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.bitmap_id = j->bitmap_id;
15508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.pixel_size = j->pixel_size;
15518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
15528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
15538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (largest_favicon_bitmaps.empty())
15558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find an icon which is larger than minimum_size_in_pixels in the order of
15588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // icon_types.
15598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FaviconBitmap largest_icon;
15608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator t = icon_types.begin();
15618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       t != icon_types.end(); ++t) {
15620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (std::map<favicon_base::IconType, FaviconBitmap>::const_iterator f =
15630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             largest_favicon_bitmaps.begin();
15640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         f != largest_favicon_bitmaps.end();
15650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++f) {
15668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (f->first & *t &&
15678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest_icon.bitmap_id == 0 ||
15688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
15698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
15708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon = f->second;
15718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
15728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
15738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
15748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon.pixel_size.height() > minimum_size_in_pixels)
15758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
15768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  GURL icon_url;
15790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
15808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
15818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &icon_type)) {
15828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::Time last_updated;
1586f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  favicon_base::FaviconRawBitmapResult bitmap_result;
15878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_url = icon_url;
15888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_type = icon_type;
15898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
15908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &last_updated,
15918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.bitmap_data,
15928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.pixel_size)) {
15938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
15948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
15958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
15968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.expired = (Time::Now() - last_updated) >
15978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      TimeDelta::FromDays(kFaviconRefetchDays);
15988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (bitmap_result.is_valid())
15998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    *favicon_bitmap_result = bitmap_result;
16008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
16028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                  TimeTicks::Now() - beginning_time);
16038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
16048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFaviconsForURL(
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1609f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
16102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_results);
16116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  GetFaviconsFromDB(page_url, icon_types, desired_sizes, bitmap_results);
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetFaviconForID(
16150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id,
16166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    int desired_size,
1617f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
16180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_ids.push_back(favicon_id);
16206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  std::vector<int> desired_sizes;
16216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  desired_sizes.push_back(desired_size);
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get results from DB.
16242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids,
16256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                      desired_sizes,
16262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bitmap_results);
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetch(
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1634f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
16352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
16366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                    desired_sizes, bitmap_results);
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MergeFavicon(
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
16412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url,
16420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
1645b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID favicon_id =
164990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!favicon_id) {
16522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is no favicon at |icon_url|, create it.
1653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
16542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
16572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
16602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // replace it.
16612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bitmap_identical = false;
16622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool replaced_bitmap = false;
16632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
16642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
16652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
16662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
16672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
16682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bitmap_identical = true;
16692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
16702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
16712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_data, base::Time::Now());
16722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        replaced_bitmap = true;
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
16742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a vector of the pixel sizes of the favicon bitmaps currently at
16792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url|.
16802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
16812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
16822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!replaced_bitmap && !bitmap_identical) {
16852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
16862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmaps are not consistent with the merged in data.
16872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delete an arbitrary favicon bitmap to avoid going over the limit of
16902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |kMaxFaviconBitmapsPerIconURL|.
16912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
16922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
16932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.erase(favicon_sizes.begin());
16942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
16952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
16962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    pixel_size);
16972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(pixel_size);
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A site may have changed the favicons that it uses for |page_url|.
17012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Example Scenario:
17022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   page_url = news.google.com
170358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //   Initial State: www.google.com/favicon.ico 16x16, 32x32
17042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
17052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //                ..., 16x16)
17062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulties:
17082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1. Sync requires that a call to GetFaviconsForURL() returns the
17092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    |bitmap_data| passed into MergeFavicon().
17102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
17112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      stay mapped to news.google.com because it would be unclear which 16x16
17122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      bitmap should be returned via GetFaviconsForURL().
17132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2. www.google.com/favicon.ico may be mapped to more than just
17152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    news.google.com (eg www.google.com).
17162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
17172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To resolve these problems, we copy all of the favicon bitmaps previously
17192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mapped to news.google.com (|page_url|) and add them to the favicon at
17202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
17212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url| are set to default to indicate that |icon_url| has incomplete
17222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // / incorrect data.
172358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
17242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //              news.google.com
17252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
17262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //               modified.
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
17292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
17322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
17332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i) {
17342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
17352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (icon_mappings[i].icon_url == icon_url)
17382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmap> bitmaps_to_copy;
17412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
17422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     &bitmaps_to_copy);
17432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
17442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Do not add a favicon bitmap at a pixel size for which there is already
17452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // a favicon bitmap mapped to |icon_url|. The one there is more correct
17462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // and having multiple equally sized favicon bitmaps for |page_url| is
17472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ambiguous in terms of GetFaviconsForURL().
17482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
17492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
17502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != favicon_sizes.end())
17512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
17522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add the favicon bitmap as expired as it is not consistent with the
17542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // merged in data.
17552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->AddFaviconBitmap(favicon_id,
17562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].bitmap_data, base::Time(),
17572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].pixel_size);
17582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
17592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
17612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
17622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
17632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
17642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the favicon mappings such that only |icon_url| is mapped to
17662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |page_url|.
17672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool mapping_changed = false;
17682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
17690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID> favicon_ids;
17702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_ids.push_back(favicon_id);
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
17722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mapping_changed = true;
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (mapping_changed || !bitmap_identical)
17762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFavicons(
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
1783f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapData>&
1784f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        favicon_bitmap_data) {
1785b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1790f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Build map of FaviconRawBitmapData for each icon url.
1791f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  typedef std::map<GURL, std::vector<favicon_base::FaviconRawBitmapData> >
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BitmapDataByIconURL;
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitmapDataByIconURL grouped_by_icon_url;
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track whether the method modifies or creates any favicon bitmaps, favicons
18002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // or icon mappings.
18012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool data_modified = false;
18022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> icon_ids;
18042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
18052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != grouped_by_icon_url.end(); ++it) {
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = it->first;
18070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id =
18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
18092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!icon_id) {
18112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Remove the favicon sizes attribute from
18122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ThumbnailDatabase::AddFavicon().
1813eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
18142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_modified = true;
18152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_ids.push_back(icon_id);
18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!data_modified)
18192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, &data_modified);
18202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
18212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, NULL);
18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_modified |=
18252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_modified) {
18282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Send notification to the UI as an icon mapping, favicon, or favicon
18292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmap was changed by this function.
18302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
18312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1838b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ ||
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &icon_mappings))
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloneFavicons(const GURL& old_page_url,
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& new_page_url) {
1852b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent cross-domain cloning.
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetImportedFavicons(
18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ImportedFaviconUsage>& favicon_usage) {
1865b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Track all URLs that had their favicons set or updated.
18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> favicons_changed;
18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_usage.size(); i++) {
18740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id =
18750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        thumbnail_db_->GetFaviconIDForFaviconURL(
18760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            favicon_usage[i].favicon_url, favicon_base::FAVICON, NULL);
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_id) {
18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This favicon doesn't exist yet, so we create it using the given data.
18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkotwicz): Pass in real pixel size.
18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_id = thumbnail_db_->AddFavicon(
18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_usage[i].favicon_url,
18820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          favicon_base::FAVICON,
18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new base::RefCountedBytes(favicon_usage[i].png_data),
18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          now,
18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::Size());
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the mapping from all the URLs to the favicon.
188946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    HistoryClient* history_client = GetHistoryClient();
18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url != favicon_usage[i].urls.end(); ++url) {
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow url_row;
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!db_->GetRowForURL(*url, &url_row)) {
18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the URL is present as a bookmark, add the url in history to
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // save the favicon mapping. This will match with what history db does
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for regular bookmarked URLs with favicons - when history db is
18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // cleaned, we keep an entry in the db with 0 visits as long as that
18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // url is bookmarked.
189946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        if (history_client && history_client->IsBookmarked(*url)) {
19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          URLRow url_info(*url);
19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_visit_count(0);
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_typed_count(0);
19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_last_visit(base::Time());
19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_hidden(false);
19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->AddURL(url_info);
19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
191090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!thumbnail_db_->GetIconMappingsForPageURL(
19110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                *url, favicon_base::FAVICON, NULL)) {
19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // URL is present in history, update the favicon *only* if it is not
19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // set already.
19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!favicons_changed.empty()) {
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the notification about the changed favicon URLs.
1923a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<FaviconChangedDetails> changed_details(
1924a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new FaviconChangedDetails);
19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.swap(favicons_changed);
19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
1927a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           changed_details.PassAs<HistoryDetails>());
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* page_url,
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
19356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
1936f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |page_url| is specified, |icon_types| must be either a single icon
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type or icon types which are equivalent.
19390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!page_url || icon_types == favicon_base::FAVICON ||
19400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_ICON ||
19410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_PRECOMPOSED_ICON ||
19420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types ==
19430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             (favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON));
19442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bitmap_results->clear();
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1946b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The icon type for which the mappings will the updated and data will be
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned.
19540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType selected_icon_type = favicon_base::INVALID_ICON;
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_urls.size(); ++i) {
19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = icon_urls[i];
19580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type_out;
19590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const favicon_base::FaviconID favicon_id =
196090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(
196190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            icon_url, icon_types, &icon_type_out);
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_id) {
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Return and update icon mappings only for the largest icon type. As
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if an |icon_url| with a larger icon type is found.
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out > selected_icon_type) {
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_icon_type = icon_type_out;
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.clear();
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out == selected_icon_type)
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.push_back(favicon_id);
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_url && !favicon_ids.empty()) {
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool mappings_updated =
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              favicon_ids);
19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappings_updated) {
19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommit();
19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_sizes,
19876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      bitmap_results);
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconBitmaps(
19910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id,
1992f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapData>& favicon_bitmap_data,
19932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* favicon_bitmaps_changed) {
19942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_bitmaps_changed)
19952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *favicon_bitmaps_changed = false;
19962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2000f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<favicon_base::FaviconRawBitmapData> to_add = favicon_bitmap_data;
20012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
20032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
2004f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapData>::iterator match_it =
20050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        to_add.end();
2006f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (std::vector<favicon_base::FaviconRawBitmapData>::iterator it =
20070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             to_add.begin();
20080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         it != to_add.end();
20090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++it) {
20102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->pixel_size == pixel_size) {
20112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        match_it = it;
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
20172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (match_it == to_add.end()) {
20182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
20192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed)
20212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *favicon_bitmaps_changed = true;
20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
20232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed &&
20242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !*favicon_bitmaps_changed &&
20252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
20262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
20272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id, base::Time::Now());
20282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
20292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
20302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Time::Now());
20312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (favicon_bitmaps_changed)
20332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *favicon_bitmaps_changed = true;
20342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
20352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      to_add.erase(match_it);
20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < to_add.size(); ++i) {
20402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
20412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time::Now(), to_add[i].pixel_size);
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_bitmaps_changed)
20442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *favicon_bitmaps_changed = true;
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool HistoryBackend::ValidateSetFaviconsParams(const std::vector<
2049f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapData>& favicon_bitmap_data) const {
20502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<GURL, size_t> BitmapsPerIconURL;
20512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BitmapsPerIconURL num_bitmaps_per_icon_url;
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2053868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!favicon_bitmap_data[i].bitmap_data.get())
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
20572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!num_bitmaps_per_icon_url.count(icon_url))
20582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_bitmaps_per_icon_url[icon_url] = 1u;
20592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
20602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++num_bitmaps_per_icon_url[icon_url];
20612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
20622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
20642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
20672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != num_bitmaps_per_icon_url.end(); ++it) {
20682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->second > kMaxFaviconBitmapsPerIconURL)
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::IsFaviconBitmapDataEqual(
20752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
20762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2077868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!new_bitmap_data.get())
20782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
20812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmap(bitmap_id,
20822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL,
20832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  &original_bitmap_data,
20842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL);
20852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_bitmap_data->Equals(original_bitmap_data);
20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconsFromDB(
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
20916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
2092f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(favicon_bitmap_results);
20942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_bitmap_results->clear();
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2096b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Time the query.
21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get FaviconIDs for |page_url| and one of |icon_types|.
21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &icon_mappings);
21060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i)
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ids.push_back(icon_mappings[i].icon_id);
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
21112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
21126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      desired_sizes, favicon_bitmap_results);
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
21152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success && !favicon_bitmap_results->empty();
21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
21190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& candidate_favicon_ids,
21206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::vector<int>& desired_sizes,
2121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_bitmap_results->clear();
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_favicon_ids.empty())
21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the FaviconID and the FaviconBitmapIDs which best match
21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |desired_size_in_dip| and |desired_scale_factors|.
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Select bitmap results from multiple favicons once
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // content::FaviconStatus supports multiple icon URLs.
21310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID best_favicon_id = 0;
21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapID> best_bitmap_ids;
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float highest_score = kSelectFaviconFramesInvalidScore;
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &bitmap_id_sizes);
21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build vector of gfx::Size from |bitmap_id_sizes|.
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<gfx::Size> sizes;
21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizes.push_back(bitmap_id_sizes[j].pixel_size);
21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<size_t> candidate_bitmap_indices;
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score = 0;
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFaviconFrameIndices(sizes,
21476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                              desired_sizes,
21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &candidate_bitmap_indices,
21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &score);
21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (score > highest_score) {
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      highest_score = score;
21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_favicon_id = candidate_favicon_ids[i],
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_bitmap_ids.clear();
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_t candidate_index = candidate_bitmap_indices[j];
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        best_bitmap_ids.push_back(
21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bitmap_id_sizes[candidate_index].bitmap_id);
21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Construct FaviconRawBitmapResults from |best_favicon_id| and
21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |best_bitmap_ids|.
21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
21650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       &icon_type)) {
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time last_updated;
2173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult bitmap_result;
21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_url = icon_url;
21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_type = icon_type;
21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &last_updated,
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.bitmap_data,
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.pixel_size)) {
21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.expired = (Time::Now() - last_updated) >
21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromDays(kFaviconRefetchDays);
21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bitmap_result.is_valid())
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
21930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
21940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
2195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find all the pages whose favicons we should set, we want to set it for
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the pages in the redirect chain if it redirected.
22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirects;
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirects);
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save page <-> favicon associations.
22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (history::RedirectList::const_iterator i(redirects.begin());
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != redirects.end(); ++i) {
22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPage(
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
22150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
22160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two icon types are considered 'equivalent' if one of the icon types is
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any favicons which are orphaned as a result of the removal of the
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon mappings.
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> unmapped_icon_ids = icon_ids;
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
22370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID>::iterator icon_id_it = std::find(
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the icon mapping already exists, avoid removing it and adding it back.
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_id_it != unmapped_icon_ids.end()) {
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unmapped_icon_ids.erase(icon_id_it);
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((icon_type == favicon_base::TOUCH_ICON &&
22470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON) ||
22480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON &&
22490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_ICON) ||
22500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == m->icon_type)) {
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->DeleteIconMapping(m->mapping_id);
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removing the icon mapping may have orphaned the associated favicon so
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we must recheck it. This is not super fast, but this case will get
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered rarely, since normally a page will always map to the same
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // favicon IDs. It will mostly happen for favicons we import.
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!thumbnail_db_->HasMappingFor(m->icon_id))
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->DeleteFavicon(m->icon_id);
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappings_changed = true;
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed = true;
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetCachedRecentRedirects(
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirect_list) {
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *redirect_list = iter->second;
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The redirect chain should have the destination URL as the last item.
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirect_list->empty());
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirect_list->back() == page_url);
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No known redirects, construct mock redirect chain containing |page_url|.
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirect_list->push_back(page_url);
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirect_list;
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirect_list);
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<FaviconChangedDetails> changed_details(new FaviconChangedDetails);
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirect_list.size(); ++i)
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.insert(redirect_list[i]);
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         changed_details.PassAs<HistoryDetails>());
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Commit() {
2300b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that a commit may not actually have been scheduled if a caller
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly calls this instead of using ScheduleCommit. Likewise, we
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may reset the flag written by a pending commit. But this is OK! It
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will merely cause extra commits (which is kind of the idea). We
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could optimize more for this case (we may get two extra commits in
23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some cases) but it hasn't been important yet.
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Somebody left a transaction open";
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleCommit() {
2324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get())
23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduled_commit_ = new CommitLaterTask(this);
232790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CancelScheduledCommit() {
2334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get()) {
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_->Cancel();
23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_ = NULL;
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTaskImpl() {
2341b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // db went away, release all the refs.
23435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    STLDeleteContainerPointers(queued_history_db_tasks_.begin(),
23445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               queued_history_db_tasks_.end());
2345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    queued_history_db_tasks_.clear();
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any canceled tasks.
2350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (!queued_history_db_tasks_.empty()) {
23515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    QueuedHistoryDBTask* task = queued_history_db_tasks_.front();
23525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!task->is_canceled())
2353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
23545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
23555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    delete task;
2356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    queued_history_db_tasks_.pop_front();
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (queued_history_db_tasks_.empty())
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the first task.
23625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<QueuedHistoryDBTask> task(queued_history_db_tasks_.front());
2363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_history_db_tasks_.pop_front();
23645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (task->Run(this, db_.get())) {
2365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // The task is done, notify the callback.
23665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    task->DoneRun();
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // The task wants to run some more. Schedule it at the end of the current
2369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // tasks, and process it after an invoke later.
23705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    queued_history_db_tasks_.push_back(task.release());
237190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generic operations
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURLs(urls);
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURL(const GURL& url) {
23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURL(url);
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ExpireHistoryBetween(
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& restrict_urls,
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time begin_time,
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time end_time) {
240458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!db_)
240558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
240758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
240858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      restrict_urls.empty()) {
240958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Special case deleting all history so it can be faster and to reduce the
241058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // possibility of an information leak.
241158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DeleteAllHistory();
241258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
241358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Clearing parts of history, have the expirer do the depend
241458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
241558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
241658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Force a commit, if the user is deleting something for privacy reasons,
241758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // we want to get it on disk ASAP.
241858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Commit();
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin_time <= first_recorded_time_)
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
24232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
24242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistoryForTimes(
24262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<base::Time>& times,
24272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time, base::Time end_time) {
2428b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (times.empty() || !db_)
24292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
24302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.begin() >= begin_time)
24322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Min time is before begin time: "
24332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
24342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.rbegin() < end_time)
24352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Max time is after end time: "
24362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
24372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::QueryOptions options;
24392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.begin_time = begin_time;
24402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.end_time = end_time;
24412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
24422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryResults results;
244346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  QueryHistoryBasic(options, &results);
24442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1st pass: find URLs that are visited at one of |times|.
24462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<GURL> urls;
24472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
24482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (times.count(results[i].visit_time()) > 0)
24492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      urls.insert(results[i].url());
24502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
24512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (urls.empty())
24522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
24532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2nd pass: collect all visit times of those URLs.
24552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Time> times_to_expire;
24562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
24572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (urls.count(results[i].url()))
24582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.push_back(results[i].visit_time());
24592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
24602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put the times in reverse chronological order and remove
24622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // duplicates (for expirer_.ExpireHistoryForTimes()).
24632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::sort(times_to_expire.begin(), times_to_expire.end(),
24642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            std::greater<base::Time>());
24652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  times_to_expire.erase(
24662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::unique(times_to_expire.begin(), times_to_expire.end()),
24672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.end());
24682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expires by times and commit.
24702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!times_to_expire.empty());
24712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expirer_.ExpireHistoryForTimes(times_to_expire);
24722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Commit();
24732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(times_to_expire.back() >= first_recorded_time_);
24752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update |first_recorded_time_| if we expired it.
24762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (times_to_expire.back() == first_recorded_time_)
24772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
24782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistory(
24812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2482b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
24832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_first_recorded_time = false;
24842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
24862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         expire_list.begin(); it != expire_list.end(); ++it) {
24872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->begin_time < first_recorded_time_)
24902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        update_first_recorded_time = true;
24912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
24922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Commit();
24932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update |first_recorded_time_| if any deletion might have affected it.
24952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (update_first_recorded_time)
24962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_->GetStartDate(&first_recorded_time_);
24972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2501b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow url_row;
25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(*i, &url_row))
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // The URL isn't in the db; nothing to do.
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector visits;
25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetVisitsForURL(url_row.id(), &visits);
25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visits.empty())
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
25187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
25197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scheduled_kill_db_ = true;
25207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Don't just do the close/delete here, as we are being called by |db| and
25217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that seems dangerous.
25227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // TODO(shess): Consider changing KillHistoryDatabase() to use
25237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // RazeAndClose().  Then it can be cleared immediately.
25247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
25257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        FROM_HERE,
25267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::Bind(&HistoryBackend::KillHistoryDatabase, this));
25277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
25287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
25297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::KillHistoryDatabase() {
25317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scheduled_kill_db_ = false;
2532b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rollback transaction because Raze() cannot be called from within a
25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RollbackTransaction();
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = db_->Raze();
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expirer keeps tabs on the active databases. Tell it about the
25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // databases which will be closed.
254846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  expirer_.SetDatabases(NULL, NULL);
25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTask(
25565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<HistoryDBTask> task,
2557116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
2558116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
2559116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool scheduled = !queued_history_db_tasks_.empty();
25605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  queued_history_db_tasks_.push_back(
25615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new QueuedHistoryDBTask(task.Pass(), origin_loop, is_canceled));
2562116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!scheduled)
25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessDBTaskImpl();
25645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::BroadcastNotifications(
25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
2568a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<HistoryDetails> details) {
25695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2570b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // HistoryService -> HistoryBackend::Closing().
2571b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
2572a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    delegate_->BroadcastNotifications(type, details.Pass());
25735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid HistoryBackend::NotifySyncURLsModified(URLRows* rows) {
25760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (typed_url_syncable_service_.get())
25770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    typed_url_syncable_service_->OnUrlsModified(rows);
25780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
25790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2580b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
258146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                           bool expired,
2582b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           URLRows* rows) {
2583b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
258446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsDeleted(all_history, expired, rows);
2585b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
2586b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deleting --------------------------------------------------------------------
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllHistory() {
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our approach to deleting all history is:
25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  1. Copy the bookmarks and their dependencies to new tables with temporary
25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     names.
25935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  2. Delete the original tables. Since tables can not share pages, we know
25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     that any data we don't want to keep is now in an unused page.
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  3. Renaming the temporary tables to match the original.
25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  4. Vacuuming the database to delete the unused pages.
25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we are likely to have very few bookmarks and their dependencies
25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compared to all history, this is also much faster than just deleting from
26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original tables directly.
26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bookmarked URLs.
260346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<URLAndTitle> starred_urls;
260446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  HistoryClient* history_client = GetHistoryClient();
260546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (history_client)
260646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    history_client->GetBookmarks(&starred_urls);
26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRows kept_urls;
26095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < starred_urls.size(); i++) {
26105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
26115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(starred_urls[i].url, &row))
26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
26135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear the last visit time so when we write these rows they are "clean."
26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_last_visit(Time());
26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_visit_count(0);
26175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_typed_count(0);
26185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kept_urls.push_back(row);
26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear thumbnail and favicon history. The favicons for the given URLs will
26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be kept.
26233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClearAllThumbnailHistory(kept_urls)) {
26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Thumbnail history could not be cleared";
26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We continue in this error case. If the user wants to delete their
26265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // history, we should delete as much as we can.
26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
263058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Therefore, we clear the list afterwards to make sure nobody uses this
263158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // invalid data.
26325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllMainHistory(kept_urls))
26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Main history could not be cleared";
26345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kept_urls.clear();
26355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
263858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Send out the notification that history is cleared. The in-memory database
26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will pick this up and clear itself.
2640a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails);
26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->all_history = true;
2642b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NotifySyncURLsDeleted(true, false, NULL);
2643a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
2644a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         details.PassAs<HistoryDetails>());
26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2648b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we have no reference to the thumbnail database, maybe there was an
26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error opening it. In this case, we just try to blow it away to try to
26515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fix the error if it exists. This may fail, in which case either the
26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file doesn't exist or there's no more we can do.
26533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sql::Connection::Delete(GetFaviconsFileName());
26543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
26553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Older version of the database.
2656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(GetThumbnailFileName());
26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Urls to retain mappings for.
26613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<GURL> urls_to_keep;
26623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin();
26633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != kept_urls.end(); ++i) {
26643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    urls_to_keep.push_back(i->url());
26653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Isolate from any long-running transaction.
26683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
26693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): If this fails, perhaps the database should be razed
26723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // or deleted.
26733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
26743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->RollbackTransaction();
26753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
26763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avaliable in HistoryBackend.
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->ClearAndroidURLRows();
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to remove all the pages associated with the dropped tables. There
26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must be no transaction open on the table when we do this. We assume that
26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our long-running transaction is open, so we complete it and start it again.
26885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thumbnail_db_->transaction_nesting() == 1);
26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
26905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->Vacuum();
26915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
26925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
26935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
26965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the duplicate URL table. We will copy the kept URLs into this.
26975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CreateTemporaryURLTable())
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
270058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Insert the URLs into the temporary table.
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
270358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    db_->AddTemporaryURL(*i);
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the original URL table with the temporary one.
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CommitTemporaryURLTable())
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the old tables and recreate them empty.
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RecreateAllTablesButURL();
27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to reclaim the space from the dropped tables. This must be done
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when there is no transaction open, and we assume that our long-running
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction is currently open.
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->Vacuum();
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)HistoryClient* HistoryBackend::GetHistoryClient() {
272546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (history_client_)
272646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    history_client_->BlockUntilBookmarksLoaded();
272746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return history_client_;
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BriefVisitInfo info;
27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.url_id = visit.url_id;
27335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.time = visit.visit_time;
27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.transition = visit.transition;
27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a delegate yet during setup or shutdown, we will drop
27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these notifications.
2737b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->NotifyVisitDBObserversOnAddVisit(info);
27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2741eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
2742eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::PopulateMostVisitedURLMap() {
2743eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MostVisitedURLList most_visited_urls;
2744116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  QueryMostVisitedURLs(
2745116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kPageVisitStatsMaxTopSites, kSegmentDataRetention, &most_visited_urls);
2746eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2748eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2749eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    most_visited_urls_map_[most_visited_urls[i].url] = i;
2750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2752eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2753eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2755eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2756eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rank = kPageVisitStatsMaxTopSites;
2757eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2758eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it != most_visited_urls_map_.end())
2759eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    rank = (*it).second;
2760eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2761eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            rank, kPageVisitStatsMaxTopSites + 1);
2762eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2763eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2764eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
2766