history_backend.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/history_url_provider.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_service.h"
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/favicon/favicon_changed_details.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_publisher.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/history/page_collector.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/page_usage_data.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/select_favicon_frames.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/common/importer/imported_favicon_usage.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/error_delegate_util.h"
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* The HistoryBackend consists of a number of components:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ArchivedDatabase (stores history older than 3 months)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (this does not store visit segments as they expire after 3 mos.)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExpireHistoryBackend (manages moving things from HistoryDatabase to
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          the ArchivedDatabase and deleting)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we keep segment data for in days. Currently 3 months.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This value needs to be greater or equal to
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dependency between MostVisitedModel and the history backend.
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kSegmentDataRetention = 90;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kCommitIntervalSeconds = 10;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time before we re-fetch the favicon.
8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kFaviconRefetchDays = 7;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleting some.
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kMaxRedirectCount = 32;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and is archived.
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kArchiveDaysThreshold = 90;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The maximum number of top sites to track when recording top page visit stats.
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const size_t kPageVisitStatsMaxTopSites = 50;
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts from PageUsageData to MostVisitedURL. |redirects| is a
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const RedirectList& redirects) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURL mv;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.url = page_data.GetURL();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.title = page_data.GetTitle();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (redirects.empty()) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirects must contain at least the target url.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects.push_back(mv.url);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects = redirects;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last url must be the target url.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mv.redirects.push_back(mv.url);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mv;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they are batched together. The important thing about this class is that
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be one of these commits still pending and holding a reference.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// task will still run (if we ever get to processing the event before
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown), but it will not do anything.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be assigned to a RunnableMethod.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in ExpireHistoryBackend).
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommitLaterTask(HistoryBackend* history_backend)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : history_backend_(history_backend) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The backend will call this function if it is being destroyed so that we
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release our reference.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_backend_ = NULL;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCommit() {
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (history_backend_.get())
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_backend_->Commit();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommitLaterTask() {}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HistoryBackend --------------------------------------------------------------
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int id,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Delegate* delegate,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkService* bookmark_service)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_(id),
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_dir_(history_dir),
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      scheduled_kill_db_(false),
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      expirer_(this, bookmark_service),
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recent_redirects_(kMaxRedirectCount),
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_destroy_message_loop_(NULL),
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_(false),
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_service_(bookmark_service) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryBackend::~HistoryBackend() {
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReleaseDBTasks();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sql::Connection::Delete(GetAndroidCacheFileName());
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Init(const std::string& languages, bool force_fail) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force_fail)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitImpl(languages);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->DBLoaded(id_);
209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
210ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  memory_pressure_listener_.reset(new base::MemoryPressureListener(
211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PopulateMostVisitedURLMap();
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const base::Closure& task) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null())
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_task_ = task;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Closing() {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any scheduled commit will have a reference to us, we must make it
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release that reference before we can be destroyed.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release our reference to the delegate, this reference will be keeping the
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // history service alive.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyRenderProcessHostDestruction(const void* host) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tracker_.NotifyRenderProcessHostDestruction(host);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetThumbnailFileName() const {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kThumbnailsFilename);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetFaviconsFileName() const {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kFaviconsFilename);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetArchivedFileName() const {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kArchivedHistoryFilename);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kAndroidCacheFilename);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is used to detect referrer loops.  Should not happen, but can
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the database is corrupt.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = from_visit;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (visit_id) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitRow row;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForVisit(visit_id, &row))
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row.segment_id)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return row.segment_id;  // Found a visit in this change with a segment.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the referrer of this visit, if any.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_id = row.referring_visit;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(visit_id) != visit_set.end()) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in referer chain, giving up";
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(visit_id);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::UpdateSegments(
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID from_visit,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID visit_id,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition_type,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time ts) {
287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only consider main frames.
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!content::PageTransitionIsMainFrame(transition_type))
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SegmentID segment_id = 0;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition t =
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition_type);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are we at the beginning of a new segment?
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that navigating to an existing entry (with back/forward) reuses the
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same transition type.  We are not adding it as a new segment in that case
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because if this was the target of a redirect, we might end up with
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2 entries for the same final URL. Ex: User types google.net, gets
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirected to google.com. A segment is created for google.net. On
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // google.com users navigates through a link, then press back. That last
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation is for the entry google.com transition typed. We end up adding
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a segment for that one as well. So we end up with google.net and google.com
30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // in the segment table, showing as 2 entries in the NTP.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note also that we should still be updating the visit count for that segment
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which we are not doing now. It should be addressed when
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://crbug.com/96860 is fixed.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((t == content::PAGE_TRANSITION_TYPED ||
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If so, create or get the segment.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string segment_name = db_->ComputeSegmentName(url);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: if we update an existing segment, we update the url used to
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // represent that segment in order to minimize stale most visited
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // images.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: it is possible there is no segment ID set for this visit chain.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TYPED. (For example GENERATED). In this case this visit doesn't count
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // toward any segment.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = GetLastSegmentID(from_visit)))
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the segment in the visit.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->SetSegmentID(visit_id, segment_id)) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, increase the counter for that segment / day.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return segment_id;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateWithPageEndTime(const void* host,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int32 page_id,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const GURL& url,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Time end_ts) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = tracker_.GetLastVisit(host, page_id, url);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisitDuration(visit_id, end_ts);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
364b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the starting visit_time for visit_id.
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_row;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetRowForVisit(visit_id, &visit_row)) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should never have a negative duration time even when time is skewed.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_row.visit_duration = end_ts > visit_row.visit_time ?
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateVisitRow(visit_row);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
378b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request.id_scope, request.page_id, request.referrer));
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID from_visit_id = last_ids.second;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a redirect chain is given, we expect the last item in that chain to be
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the final URL.
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request.redirects.empty() ||
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         request.redirects.back() == request.url);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is adding older history, we need to make sure our times
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are correct.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request.time < first_recorded_time_)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = request.time;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition request_transition = request.transition;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition stripped_transition =
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransitionStripQualifier(request_transition);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_generated =
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is navigating to a not-previously-typed intranet hostname,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the transition to TYPED so that the omnibox will learn that this is
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a known host.
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_redirects = request.redirects.size() > 1;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (content::PageTransitionIsMainFrame(request_transition) &&
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url(has_redirects ?
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request.redirects[0] : request.url);
412d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (origin_url.SchemeIs(content::kHttpScheme) ||
413424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        origin_url.SchemeIs(content::kHttpsScheme) ||
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        origin_url.SchemeIs(chrome::kFtpScheme)) {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string host(origin_url.host());
416a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      size_t registry_length =
417a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          net::registry_controlled_domains::GetRegistryLength(
418a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              host,
419a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
420a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
421a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (registry_length == 0 && !db_->IsTypedHost(host)) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stripped_transition = content::PAGE_TRANSITION_TYPED;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition =
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::PageTransitionFromInt(
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                stripped_transition |
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                content::PageTransitionGetQualifier(request_transition));
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_redirects) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The single entry is both a chain start and end.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition t = content::PageTransitionFromInt(
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition |
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START |
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_END);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect case (one element means just the page itself).
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_ids = AddPageVisit(request.url, request.time,
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            last_ids.second, t, request.visit_source);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the segment for this visit. KEYWORD_GENERATED visits should not
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result in changing most visited, so we don't update segments (most
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // visited db).
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_keyword_generated) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     request.time);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the referrer's duration.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateVisitDuration(from_visit_id, request.time);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirect case. Add the redirect chain.
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition redirect_info =
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects = request.redirects;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (redirects[0].SchemeIs(chrome::kAboutScheme)) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the redirect source + referrer is "about" we skip it. This
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // happens when a page opens a new frame/window to about:blank and then
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // script sets the URL to somewhere else (used to hide the referrer). It
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would be nice to keep all these redirects properly but we don't ever
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // see the initial about:blank load, so we don't know where the
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // subsequent client redirect came from.
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this case, we just don't bother hooking up the source of the
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects, so we remove it.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirects.erase(redirects.begin());
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The first entry in the redirect chain initiated a client redirect.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't add this to the database since the referrer is already
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // there, so we skip over it but change the transition type of the first
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transition to client redirect.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The referrer is invalid when restoring a session that features an
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // https tab that redirects to a different host or to http. In this
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case we don't need to reconnect the new redirect with the existing
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // chain.
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (request.referrer.is_valid()) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(request.referrer == redirects[0]);
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        redirects.erase(redirects.begin());
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the navigation entry for this visit has replaced that for the
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // first visit, remove the CHAIN_END marker from the first visit. This
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can be called a lot, for example, the page cycler, and most of the
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // time we won't have changed anything.
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisitRow visit_row;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (request.did_replace_entry &&
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db_->GetRowForVisit(last_ids.second, &visit_row) &&
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          visit_row.transition = content::PageTransitionFromInt(
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->UpdateVisitRow(visit_row);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t redirect_index = 0; redirect_index < redirects.size();
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         redirect_index++) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransition t =
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::PageTransitionFromInt(stripped_transition | redirect_info);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If this is the last transition, add a CHAIN_END marker
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (redirect_index == (redirects.size() - 1)) {
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t = content::PageTransitionFromInt(
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            t | content::PAGE_TRANSITION_CHAIN_END);
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Record all redirect visits with the same timestamp. We don't display
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them anyway, and if we ever decide to, we can reconstruct their order
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the redirect chain.
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_ids = AddPageVisit(redirects[redirect_index],
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              request.time, last_ids.second,
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              t, request.visit_source);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (t & content::PAGE_TRANSITION_CHAIN_START) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the segment for this visit.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateSegments(redirects[redirect_index],
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       from_visit_id, last_ids.second, t, request.time);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the visit_details for this visit.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateVisitDuration(from_visit_id, request.time);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Subsequent transitions in the redirect list must all be server
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects.
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last, save this redirect chain for later so we can set titles & favicons
532bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // on the redirected pages properly.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recent_redirects_.Put(request.url, redirects);
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the last visit to the tracker so we can get outgoing transitions.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation anyway, so last_visit_id is always zero for them.  But adding
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them here confuses main frame history, so we skip them for now.
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tracker_.AddVisit(request.id_scope, request.page_id, request.url,
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      last_ids.second);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (page_collector_)
55168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    page_collector_->AddPageURL(request.url, request.time);
55268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::InitImpl(const std::string& languages) {
557b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!db_) << "Initializing HistoryBackend twice";
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the rare case where the db fails to initialize a dialog may get shown
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the blocks the caller, yet allows other messages through. For this reason
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only set db_ to the created database if creation is successful. That
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way other methods won't do anything as db_ is still NULL.
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Compute the file names.
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
5673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::FilePath thumbnail_name = GetFaviconsFileName();
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath archived_name = GetArchivedFileName();
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
570bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete the old index database files which are no longer used.
571bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DeleteFTSIndexDatabases();
572bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // History database.
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new HistoryDatabase());
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Unretained to avoid a ref loop with db_.
5777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  db_->set_error_callback(
5787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Bind(&HistoryBackend::DatabaseErrorCallback,
5797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                 base::Unretained(this)));
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  sql::InitStatus status = db_->Init(history_name);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_OK:
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_FAILURE: {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A NULL db_ will cause all calls on this object to notice this error
5877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // and to not continue. If the error callback scheduled killing the
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database, the task it posted has not executed yet. Try killing the
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database now before we close it.
5907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      bool kill_db = scheduled_kill_db_;
5917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (kill_db)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        KillHistoryDatabase();
5937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->NotifyProfileError(id_, status);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the in-memory database and send it back to the history service on the
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // main thread.
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mem_backend->Init(history_name, db_.get()))
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->SetInMemoryBackend(id_, mem_backend);  // Takes ownership of
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      // pointer.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete mem_backend;  // Error case, run without the in-memory DB.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
612bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Create the history publisher which needs to be passed on to the thumbnail
613bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // database for publishing history.
61468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TODO(shess): HistoryPublisher is being deprecated.  I am still
61568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // trying to track down who depends on it, meanwhile talk to me
61668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // before removing interactions with it.  http://crbug.com/294306
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_publisher_.reset(new HistoryPublisher());
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!history_publisher_->Init()) {
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The init may fail when there are no indexers wanting our history.
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Hence no need to log the failure.
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_publisher_.reset();
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
62468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Collects page data for history_publisher_.
62568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (history_publisher_.get()) {
62668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    page_collector_.reset(new PageCollector());
62768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    page_collector_->Init(history_publisher_.get());
62868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
62968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Thumbnail database.
6313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): "thumbnail database" these days only stores
6323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // favicons.  Thumbnails are stored in "top sites".  Consider
6333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // renaming "thumbnail" references to "favicons" or something of the
6343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // sort.
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_.reset(new ThumbnailDatabase());
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thumbnail_db_->Init(thumbnail_name,
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          db_.get()) != sql::INIT_OK) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unlike the main database, we don't error out when the database is too
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new because this error is much less severe. Generally, this shouldn't
64058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // happen since the thumbnail and main database versions should be in sync.
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We'll just continue without thumbnails & favicons in this case or any
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other error.
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the thumbnail database.";
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Archived database.
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->needs_version_17_migration()) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See needs_version_17_migration() decl for more. In this case, we want
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to delete the archived database and need to do so before we try to
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // open the file. We can ignore any error (maybe the file doesn't exist).
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(archived_name);
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  archived_db_.reset(new ArchivedDatabase());
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!archived_db_->Init(archived_name)) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the archived database.";
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Generate the history and thumbnail database metrics only after performing
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any migration work.
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::RandInt(1, 100) == 50) {
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only do this computation sometimes since it can be expensive.
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->ComputeDatabaseMetrics(history_name);
6652385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (thumbnail_db_)
6662385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      thumbnail_db_->ComputeDatabaseMetrics();
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tell the expiration module about all the nice databases we made. This must
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // happen before db_->Init() is called since the callback ForceArchiveHistory
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may need to expire stuff.
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // *sigh*, this can all be cleaned up when that migration code is removed.
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The main DB initialization should intuitively be first (not that it
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // actually matters) and the expirer should be set last.
67668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  expirer_.SetDatabases(db_.get(), archived_db_.get(), thumbnail_db_.get());
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the long-running transaction.
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
680b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
682b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the first item in our database.
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start expiring old stuff.
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
692b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    android_provider_backend_.reset(new AndroidProviderBackend(
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetAndroidCacheFileName(), db_.get(), thumbnail_db_.get(),
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bookmark_service_, delegate_.get()));
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HISTOGRAM_TIMES("History.InitTime",
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  TimeTicks::Now() - beginning_time);
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
703ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid HistoryBackend::OnMemoryPressure(
704ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
705ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool trim_aggressively = memory_pressure_level ==
706ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
707ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (db_)
708ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    db_->TrimMemory(trim_aggressively);
709ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (thumbnail_db_)
710ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    thumbnail_db_->TrimMemory(trim_aggressively);
711ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (archived_db_)
712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    archived_db_->TrimMemory(trim_aggressively);
713ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
714ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloseAllDatabases() {
716b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the long-running transaction.
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->CommitTransaction();
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset();
72058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Forget the first recorded time since the database is closed.
72158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    first_recorded_time_ = base::Time();
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
723b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
727b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time time,
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID referring_visit,
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitSource visit_source) {
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Top-level frame navigations are visible, everything else is hidden
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool new_hidden = !content::PageTransitionIsMainFrame(transition);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This code must stay in sync with
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExpireHistoryBackend::ExpireURLsForVisits().
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // typed, which would eliminate the need for this code.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int typed_increment = 0;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition transition_type =
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((transition_type == content::PAGE_TRANSITION_TYPED &&
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !content::PageTransitionIsRedirect(transition)) ||
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typed_increment = 1;
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
755eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Only count the page visit if it came from user browsing and only count it
756eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // once when cycling through a redirect chain.
757eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (visit_source == SOURCE_BROWSED &&
758eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
759eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordTopPageVisitStats(url);
760eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
761eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
762eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if this URL is already in the DB.
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update of an existing row.
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::PageTransitionStripQualifier(transition) !=
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_RELOAD)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_visit_count(url_info.visit_count() + 1);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (typed_increment)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_typed_count(url_info.typed_count() + typed_increment);
773c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (url_info.last_visit() < time)
774c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_info.set_last_visit(time);
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only allow un-hiding of pages, never hiding.
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_hidden)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_hidden(false);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateURLRow(url_id, url_info);
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Addition of a new row.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_visit_count(1);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_typed_count(typed_increment);
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_last_visit(time);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_hidden(new_hidden);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_id = db_->AddURL(url_info);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Adding URL failed.";
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::make_pair(0, 0);
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.id_ = url_id;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the visit with the time to the database.
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyVisitObservers(visit_info);
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_info.visit_time < first_recorded_time_)
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = visit_info.visit_time;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification of the visit.
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id) {
806b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
807b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
808b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLVisitedDetails* details = new URLVisitedDetails;
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->transition = transition;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->row = url_info;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // GetMostRecentRedirectsTo(url, &details->redirects);
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED, details);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
826b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We will add to either the archived database or the main one depending on
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the date of the added visit.
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLDatabase* url_database;
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitDatabase* visit_database;
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit())) {
838b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      if (!archived_db_)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;  // No archived database to save it to, just forget this.
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = archived_db_.get();
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = archived_db_.get();
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = db_.get();
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = db_.get();
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = url_database->GetRowForURL(i->url(), &existing_url);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_id = url_database->AddURL(*i);
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i->typed_count() > 0) {
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        modified->changed_urls.push_back(*i);
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        modified->changed_urls.back().set_id(url_id);  // *i likely has |id_| 0.
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // TODO(shess): I'm not sure this case needs to exist anymore.
86468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (page_collector_) {
86568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      page_collector_->AddPageData(i->url(), i->last_visit(),
86668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                   i->title(), string16());
86768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
86868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          content::PageTransitionFromInt(
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_LINK |
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_START |
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_END), 0);
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!visit_database->AddVisit(&visit_info, visit_source)) {
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
888b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
889b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
890b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         modified.release());
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return time < expirer_.GetCurrentArchiveTime();
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
90668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url, const string16& title) {
907b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
91068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (page_collector_)
91168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    page_collector_->AddPageTitle(url, title);
91268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
946b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
947b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           details.release());
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               const string16& title) {
956b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(UTF8ToUTF16(url.spec()));
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
98090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
982b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
9872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
997b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
1003b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int max_visits,
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               VisitVector* visits) {
1011b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
1017b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->UpdateURLRow(id, url);
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::AddVisits(const GURL& url,
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<VisitInfo>& visits,
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               VisitSource visit_source) {
1025b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         visit != visits.end(); ++visit) {
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!AddPageVisit(
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              url, visit->first, 0, visit->second, visit_source).first) {
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1040b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.ExpireVisits(visits);
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VisitSourceMap* sources) {
1050b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetVisitsSource(visits, sources);
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1058b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetRowForURL(url, url_row) != 0;
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryURL(scoped_refptr<QueryURLRequest> request,
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const GURL& url,
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool want_visits) {
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow* row = &request->value.a;
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector* visits = &request->value.b;
1072b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetRowForURL(url, row)) {
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Have a row.
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = true;
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Optionally query the visits.
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (want_visits)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetVisitsForURL(row->id(), visits);
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, row, visits);
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1086b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return typed_url_syncable_service_.get();
1087b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1088b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Segment usage ---------------------------------------------------------------
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteOldSegmentData() {
1092b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->DeleteSegmentData(Time::Now() -
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           TimeDelta::FromDays(kSegmentDataRetention));
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QuerySegmentUsage(
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time from_time,
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_result_count) {
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this is the first time we query segments, invoke
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DeleteOldSegmentData asynchronously. We do this to cleanup old
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // entries.
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!segment_queried_) {
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_ = true;
111290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->PostTask(
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IncreaseSegmentDuration(const GURL& url,
11212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::Time time,
11222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::TimeDelta delta) {
1123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string segment_name(VisitSegmentDatabase::ComputeSegmentName(url));
11272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SegmentID segment_id = db_->GetSegmentNamed(segment_name);
11282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!segment_id) {
11292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
11302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!url_id)
11312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
11322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    segment_id = db_->CreateSegment(url_id, segment_name);
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!segment_id)
11342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
11352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SegmentDurationID duration_id;
11372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta total_delta;
11382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_->GetSegmentDuration(segment_id, time, &duration_id,
11392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               &total_delta)) {
11402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->CreateSegmentDuration(segment_id, time, delta);
11412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  total_delta += delta;
11442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->SetSegmentDuration(duration_id, total_delta);
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QuerySegmentDuration(
11482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time from_time,
11502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int max_result_count) {
11512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (request->canceled())
11522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QuerySegmentDuration(from_time, max_result_count,
11562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              &request->value.get());
11572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
11592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keyword visits --------------------------------------------------------------
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 TemplateURLID keyword_id,
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 const string16& term) {
1166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the ID for this URL.
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_row;
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->GetRowForURL(url, &url_row)) {
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a small possibility the url was deleted before the keyword
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was added. Ignore the request.
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->SetKeywordSearchTermsForURL(url_row.id(), keyword_id, term);
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // details is deleted by BroadcastNotifications.
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KeywordSearchTermDetails* details = new KeywordSearchTermDetails;
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->url = url;
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->keyword_id = keyword_id;
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->term = term;
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, details);
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllSearchTermsForKeyword(
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id) {
1191b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->DeleteAllSearchTermsForKeyword(keyword_id);
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky): bug 1168470. Need to move from archive dbs too.
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetMostRecentKeywordSearchTerms(
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id,
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& prefix,
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_count) {
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &(request->value));
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Downloads -------------------------------------------------------------------
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::GetNextDownloadId(uint32* next_id) {
1217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
12187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    db_->GetNextDownloadId(next_id);
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get all the download entries from the database.
12222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1223b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
12242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QueryDownloads(rows);
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update a particular download entry.
12282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1229b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->UpdateDownload(data);
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::CreateDownload(const history::DownloadRow& history_info,
12367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    bool* success) {
1237b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  *success = db_->CreateDownload(history_info);
12402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1244b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_before = db_->CountDownloads();
12472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks started_removing = base::TimeTicks::Now();
12482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HistoryBackend uses a long-running Transaction that is committed
12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // periodically, so this loop doesn't actually hit the disk too hard.
12507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::set<uint32>::const_iterator it = ids.begin();
12517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       it != ids.end(); ++it) {
12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->RemoveDownload(*it);
12532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScheduleCommit();
12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks finished_removing = base::TimeTicks::Now();
12567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_after = db_->CountDownloads();
12577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
12587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_LE(downloads_count_after, downloads_count_before);
12597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (downloads_count_after > downloads_count_before)
12607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
12627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
12637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        num_downloads_deleted);
12647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeDelta micros = (1000 * (finished_removing - started_removing));
12657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
12667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (num_downloads_deleted > 0) {
12677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
12687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        (1000 * micros) / num_downloads_deleted);
12692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GE(ids.size(), num_downloads_deleted);
12717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (ids.size() < num_downloads_deleted)
12727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
12747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        ids.size() - num_downloads_deleted);
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const string16& text_query,
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const QueryOptions& options) {
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (text_query.empty()) {
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Basic history query for the main database.
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Now query the archived database. This is a bit tricky because we don't
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // want to query it if the queried time range isn't going to find anything
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // in it.
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(brettw) bug 1171036: do blimpie querying for the archived database
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // as well.
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if (archived_db_.get() &&
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Text history query.
1299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      QueryHistoryText(db_.get(), db_.get(), text_query, options,
1300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                       &request->value);
1301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (archived_db_.get() &&
1302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          expirer_.GetCurrentArchiveTime() >= options.begin_time) {
1303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        QueryHistoryText(archived_db_.get(), archived_db_.get(), text_query,
1304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         options, &request->value);
1305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.QueryHistory",
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic time-based querying of history.
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       VisitDatabase* visit_db,
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const QueryOptions& options,
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QueryResults* result) {
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First get all visits.
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
13222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits);
13232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add them and the URL rows to the results.
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); i++) {
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VisitRow visit = visits[i];
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add a result row for this visit, get the URL info from the DB.
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_db->GetURLRow(visit.url_id, &url_result)) {
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to get id " << visit.url_id
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " from history.urls.";
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // DB out of sync and URL doesn't exist, try to recover.
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid()) {
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Got invalid URL from history.urls with id "
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << visit.url_id << ":  "
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << url_result.url().possibly_invalid_spec();
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The archived database may be out of sync with respect to starring,
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // titles, last visit date, etc. Therefore, we query the main DB if the
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // current URL database is not the main one.
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url_db == db_.get()) {
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Currently querying the archived DB, update with the main database to
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // catch any interesting stuff. This will update it if it exists in the
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // main DB, and do nothing otherwise.
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetRowForURL(url_result.url(), &url_result);
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(visit.visit_time);
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Set whether the visit was blocked for a managed user by looking at the
1357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // transition type.
1358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url_result.set_blocked_visit(
1359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't set any of the query-specific parts of the URLResult, since
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // snippets and stuff don't apply to basic querying.
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_more_results && options.begin_time <= first_recorded_time_)
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Text-based querying of history.
1371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::QueryHistoryText(URLDatabase* url_db,
1372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      VisitDatabase* visit_db,
1373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const string16& text_query,
1374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const QueryOptions& options,
1375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      QueryResults* result) {
1376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  URLRows text_matches;
1377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  url_db->GetTextMatches(text_query, &text_matches);
1378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<URLResult> matching_visits;
1380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VisitVector visits;    // Declare outside loop to prevent re-construction.
1381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < text_matches.size(); i++) {
1382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const URLRow& text_match = text_matches[i];
1383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Get all visits for given URL match.
1384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    visit_db->GetVisitsForURLWithOptions(text_match.id(), options, &visits);
1385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < visits.size(); j++) {
1386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      URLResult url_result(text_match);
1387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_result.set_visit_time(visits[j].visit_time);
1388eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      matching_visits.push_back(url_result);
1389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::sort(matching_visits.begin(), matching_visits.end(),
1393eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            URLResult::CompareVisitTime);
1394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t max_results = options.max_count == 0 ?
1396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (std::vector<URLResult>::iterator it = matching_visits.begin();
1398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != matching_visits.end() && result->size() < max_results; ++it) {
1399eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->AppendURLBySwapping(&(*it));
1400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1402eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (matching_visits.size() == result->size() &&
1403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      options.begin_time <= first_recorded_time_)
1404eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->set_reached_beginning(true);
1405eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1406eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Frontend to GetMostRecentRedirectsFrom from the history thread.
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsFrom(
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsFrom(url, &request->value);
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsTo(
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsTo(url, &request->value);
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetVisibleVisitCountToHost(
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetVisibleVisitCountToHostRequest> request,
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time first_visit;
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool success = db_.get() &&
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, count, first_visit);
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryTopURLsAndRedirects(
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count) {
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1444b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), false, NULL, NULL);
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL>* top_urls = &request->value.a;
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectMap* redirects = &request->value.b;
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_count, &data.get());
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_urls->push_back(data[i]->GetURL());
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*redirects)[top_urls->back()] = list;
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), true, top_urls, redirects);
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Will replace QueryTopURLsAndRedirectsRequest.
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLs(
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryMostVisitedURLsRequest> request,
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count,
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int days_back) {
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1474b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), MostVisitedURLList());
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURLList* result = &request->value;
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  QueryMostVisitedURLsImpl(result_count, days_back, result);
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), *result);
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryFilteredURLs(
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<QueryFilteredURLsRequest> request,
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int result_count,
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const history::VisitFilter& filter,
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool extended_info)  {
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time request_start = base::Time::Now();
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), FilteredURLList());
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, double> score_map;
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); ++i) {
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(georgey): experiment with visit_segment database granularity (it is
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently 24 hours) to use it directly instead of using visits database,
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is considerably slower.
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.reserve(score_map.size());
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<URLID, double>::iterator it = score_map.begin();
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != score_map.end(); ++it) {
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* pud = new PageUsageData(it->first);
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pud->SetScore(it->second);
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.push_back(pud);
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit to the top |result_count| results.
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
15232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_count && implicit_cast<int>(data.size()) > result_count)
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.resize(result_count);
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow info;
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetURLRow(data[i]->GetID(), &info)) {
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetURL(info.url());
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetTitle(info.title());
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilteredURLList& result = request->value;
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilteredURL url(*current_data);
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extended_info) {
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitVector visits;
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisitsForURL(current_data->GetID(), &visits);
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits.size() > 0) {
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url.extended_info.total_visits = visits.size();
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < visits.size(); ++i) {
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url.extended_info.duration_opened +=
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visits[i].visit_duration.InSeconds();
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (visits[i].visit_time > url.extended_info.last_visit_time) {
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url.extended_info.last_visit_time = visits[i].visit_time;
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(macourteau): implement the url.extended_info.visits stat.
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.push_back(url);
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta_time = std::max(1, std::min(999,
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATIC_HISTOGRAM_POINTER_BLOCK(
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NewTabPage.SuggestedSitesLoadTime",
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Add(delta_time),
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), result);
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              int days_back,
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              MostVisitedURLList* result) {
1571b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() -
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromDays(days_back),
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         result_count, &data.get());
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects;
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back(url);
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsFromSpecificVisit(
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit, history::RedirectList* redirects) {
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow any redirects from the given visit and add them to the list.
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It *should* be impossible to get a circular chain here, but we check
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just in case to avoid infinite loops.
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsToSpecificVisit(
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit,
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow redirects going to cur_visit. These are added to |redirects| in
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the order they are found. If a redirect chain looks like A -> B -> C and
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |cur_visit| = C, redirects will be {B, A} in that order.
1612b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsFrom(
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& from_url,
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1632b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsFromSpecificVisit(cur_visit, redirects);
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsTo(
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& to_url,
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1648b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsToSpecificVisit(cur_visit, redirects);
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          HistoryURLProviderParams* params) {
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExecuteWithDB should handle the NULL database case.
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->ExecuteWithDB(this, db_.get(), params);
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1666bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid HistoryBackend::DeleteFTSIndexDatabases() {
1667bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Find files on disk matching the text databases file pattern so we can
1668bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // quickly test for and delete them.
1669bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath::StringType filepattern =
1670bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FILE_PATH_LITERAL("History Index *");
1671bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FileEnumerator enumerator(
1672bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      history_dir_, false, base::FileEnumerator::FILES, filepattern);
1673bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  int num_databases_deleted = 0;
1674bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath current_file;
1675bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  while (!(current_file = enumerator.Next()).empty()) {
1676bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (sql::Connection::Delete(current_file))
1677bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      num_databases_deleted++;
1678bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1679bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1680bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                       num_databases_deleted);
1681bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
1682bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
168368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void HistoryBackend::SetPageContents(const GURL& url,
168468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                     const string16& contents) {
168568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (page_collector_)
168668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    page_collector_->AddPageContents(url, contents);
168768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
168868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFavicons(
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
16932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
169490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
16952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types,
16962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
16972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFaviconsForURL(
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
17042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
170590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
17062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_results);
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconsFromDB(page_url, icon_types, desired_size_in_dip,
17082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    desired_scale_factors, bitmap_results);
17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetFaviconForID(
171290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID favicon_id,
17132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int desired_size_in_dip,
17142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ScaleFactor desired_scale_factor,
171590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
171690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> favicon_ids;
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_ids.push_back(favicon_id);
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::ScaleFactor> desired_scale_factors;
17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desired_scale_factors.push_back(desired_scale_factor);
17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get results from DB.
17222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids,
17232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_size_in_dip,
17242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_scale_factors,
17252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bitmap_results);
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetch(
17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
17332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
173490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
17352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
17362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
17372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MergeFavicon(
17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url,
174390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
1746b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
174990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::FaviconID favicon_id =
175090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!favicon_id) {
17532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is no favicon at |icon_url|, create it.
1754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
17552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
17582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
17612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // replace it.
17622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bitmap_identical = false;
17632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool replaced_bitmap = false;
17642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
17652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
17662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
17672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
17682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
17692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bitmap_identical = true;
17702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
17712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
17722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_data, base::Time::Now());
17732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        replaced_bitmap = true;
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
17752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a vector of the pixel sizes of the favicon bitmaps currently at
17802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url|.
17812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
17822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
17832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!replaced_bitmap && !bitmap_identical) {
17862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
17872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmaps are not consistent with the merged in data.
17882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delete an arbitrary favicon bitmap to avoid going over the limit of
17912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |kMaxFaviconBitmapsPerIconURL|.
17922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
17932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
17942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.erase(favicon_sizes.begin());
17952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
17962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
17972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    pixel_size);
17982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(pixel_size);
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A site may have changed the favicons that it uses for |page_url|.
18022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Example Scenario:
18032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   page_url = news.google.com
180458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //   Initial State: www.google.com/favicon.ico 16x16, 32x32
18052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
18062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //                ..., 16x16)
18072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulties:
18092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1. Sync requires that a call to GetFaviconsForURL() returns the
18102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    |bitmap_data| passed into MergeFavicon().
18112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
18122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      stay mapped to news.google.com because it would be unclear which 16x16
18132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      bitmap should be returned via GetFaviconsForURL().
18142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2. www.google.com/favicon.ico may be mapped to more than just
18162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    news.google.com (eg www.google.com).
18172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
18182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To resolve these problems, we copy all of the favicon bitmaps previously
18202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mapped to news.google.com (|page_url|) and add them to the favicon at
18212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
18222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url| are set to default to indicate that |icon_url| has incomplete
18232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // / incorrect data.
182458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
18252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //              news.google.com
18262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
18272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //               modified.
18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
18302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
18332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
18342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i) {
18352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
18362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (icon_mappings[i].icon_url == icon_url)
18392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmap> bitmaps_to_copy;
18422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
18432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     &bitmaps_to_copy);
18442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
18452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Do not add a favicon bitmap at a pixel size for which there is already
18462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // a favicon bitmap mapped to |icon_url|. The one there is more correct
18472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // and having multiple equally sized favicon bitmaps for |page_url| is
18482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ambiguous in terms of GetFaviconsForURL().
18492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
18502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
18512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != favicon_sizes.end())
18522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
18532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add the favicon bitmap as expired as it is not consistent with the
18552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // merged in data.
18562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->AddFaviconBitmap(favicon_id,
18572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].bitmap_data, base::Time(),
18582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].pixel_size);
18592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
18602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
18622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
18632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the favicon mappings such that only |icon_url| is mapped to
18672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |page_url|.
18682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool mapping_changed = false;
18692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
187090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconID> favicon_ids;
18712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_ids.push_back(favicon_id);
18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
18732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mapping_changed = true;
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (mapping_changed || !bitmap_identical)
18772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFavicons(
18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
188390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
188490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data) {
1885b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build map of FaviconBitmapData for each icon url.
189190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  typedef std::map<GURL, std::vector<chrome::FaviconBitmapData> >
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BitmapDataByIconURL;
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitmapDataByIconURL grouped_by_icon_url;
18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track whether the method modifies or creates any favicon bitmaps, favicons
19002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // or icon mappings.
19012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool data_modified = false;
19022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
190390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> icon_ids;
19042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
19052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != grouped_by_icon_url.end(); ++it) {
19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = it->first;
190790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID icon_id =
19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
19092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!icon_id) {
19112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Remove the favicon sizes attribute from
19122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ThumbnailDatabase::AddFavicon().
1913eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
19142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_modified = true;
19152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_ids.push_back(icon_id);
19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!data_modified)
19192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, &data_modified);
19202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
19212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, NULL);
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_modified |=
19252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_modified) {
19282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Send notification to the UI as an icon mapping, favicon, or favicon
19292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmap was changed by this function.
19302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
19312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1938b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ ||
19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &icon_mappings))
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloneFavicons(const GURL& old_page_url,
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& new_page_url) {
1952b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent cross-domain cloning.
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetImportedFavicons(
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ImportedFaviconUsage>& favicon_usage) {
1965b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Track all URLs that had their favicons set or updated.
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> favicons_changed;
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_usage.size(); i++) {
197490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL(
197590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        favicon_usage[i].favicon_url, chrome::FAVICON, NULL);
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_id) {
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This favicon doesn't exist yet, so we create it using the given data.
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkotwicz): Pass in real pixel size.
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_id = thumbnail_db_->AddFavicon(
19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_usage[i].favicon_url,
198190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          chrome::FAVICON,
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new base::RefCountedBytes(favicon_usage[i].png_data),
19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          now,
19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::Size());
19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the mapping from all the URLs to the favicon.
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkService* bookmark_service = GetBookmarkService();
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url != favicon_usage[i].urls.end(); ++url) {
19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow url_row;
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!db_->GetRowForURL(*url, &url_row)) {
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the URL is present as a bookmark, add the url in history to
19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // save the favicon mapping. This will match with what history db does
19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for regular bookmarked URLs with favicons - when history db is
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // cleaned, we keep an entry in the db with 0 visits as long as that
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // url is bookmarked.
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (bookmark_service && bookmark_service_->IsBookmarked(*url)) {
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          URLRow url_info(*url);
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_visit_count(0);
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_typed_count(0);
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_last_visit(base::Time());
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_hidden(false);
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->AddURL(url_info);
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
200990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!thumbnail_db_->GetIconMappingsForPageURL(
201090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                *url, chrome::FAVICON, NULL)) {
20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // URL is present in history, update the favicon *only* if it is not
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // set already.
20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!favicons_changed.empty()) {
20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the notification about the changed favicon URLs.
202290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    FaviconChangedDetails* changed_details = new FaviconChangedDetails;
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.swap(favicons_changed);
20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           changed_details);
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* page_url,
20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
20342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
203590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |page_url| is specified, |icon_types| must be either a single icon
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type or icon types which are equivalent.
20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!page_url ||
203990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == chrome::FAVICON ||
204090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == chrome::TOUCH_ICON ||
204190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == chrome::TOUCH_PRECOMPOSED_ICON ||
204290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == (chrome::TOUCH_ICON | chrome::TOUCH_PRECOMPOSED_ICON));
20432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bitmap_results->clear();
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
204990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> favicon_ids;
20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The icon type for which the mappings will the updated and data will be
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned.
205390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::IconType selected_icon_type = chrome::INVALID_ICON;
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_urls.size(); ++i) {
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = icon_urls[i];
205790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type_out;
205890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const chrome::FaviconID favicon_id =
205990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(
206090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            icon_url, icon_types, &icon_type_out);
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_id) {
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Return and update icon mappings only for the largest icon type. As
20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if an |icon_url| with a larger icon type is found.
20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out > selected_icon_type) {
20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_icon_type = icon_type_out;
20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.clear();
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out == selected_icon_type)
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.push_back(favicon_id);
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_url && !favicon_ids.empty()) {
20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool mappings_updated =
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              favicon_ids);
20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappings_updated) {
20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommit();
20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_size_in_dip,
20862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_scale_factors, bitmap_results);
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconBitmaps(
209090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID icon_id,
209190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data,
20922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* favicon_bitmaps_changed) {
20932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_bitmaps_changed)
20942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *favicon_bitmaps_changed = false;
20952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
209990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconBitmapData> to_add = favicon_bitmap_data;
21002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
21022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
210390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapData>::iterator match_it = to_add.end();
210490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (std::vector<chrome::FaviconBitmapData>::iterator it = to_add.begin();
21052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != to_add.end(); ++it) {
21062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->pixel_size == pixel_size) {
21072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        match_it = it;
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
21132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (match_it == to_add.end()) {
21142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
21152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed)
21172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *favicon_bitmaps_changed = true;
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
21192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed &&
21202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !*favicon_bitmaps_changed &&
21212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
21222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
21232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id, base::Time::Now());
21242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
21252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
21262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Time::Now());
21272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (favicon_bitmaps_changed)
21292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *favicon_bitmaps_changed = true;
21302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
21312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      to_add.erase(match_it);
21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < to_add.size(); ++i) {
21362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
21372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time::Now(), to_add[i].pixel_size);
21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_bitmaps_changed)
21402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *favicon_bitmaps_changed = true;
21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::ValidateSetFaviconsParams(
214590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data) const {
21462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<GURL, size_t> BitmapsPerIconURL;
21472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BitmapsPerIconURL num_bitmaps_per_icon_url;
21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!favicon_bitmap_data[i].bitmap_data.get())
21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
21532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!num_bitmaps_per_icon_url.count(icon_url))
21542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_bitmaps_per_icon_url[icon_url] = 1u;
21552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
21562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++num_bitmaps_per_icon_url[icon_url];
21572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
21582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
21602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
21632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != num_bitmaps_per_icon_url.end(); ++it) {
21642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->second > kMaxFaviconBitmapsPerIconURL)
21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::IsFaviconBitmapDataEqual(
21712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
21722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!new_bitmap_data.get())
21742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
21772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmap(bitmap_id,
21782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL,
21792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  &original_bitmap_data,
21802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL);
21812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_bitmap_data->Equals(original_bitmap_data);
21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconsFromDB(
21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
218990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(favicon_bitmap_results);
21912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_bitmap_results->clear();
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Time the query.
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get FaviconIDs for |page_url| and one of |icon_types|.
22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &icon_mappings);
220390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> favicon_ids;
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i)
22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ids.push_back(icon_mappings[i].icon_id);
22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
22082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
22092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_size_in_dip, desired_scale_factors, favicon_bitmap_results);
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
22122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success && !favicon_bitmap_results->empty();
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
221690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconID>& candidate_favicon_ids,
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
221990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_bitmap_results->clear();
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_favicon_ids.empty())
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the FaviconID and the FaviconBitmapIDs which best match
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |desired_size_in_dip| and |desired_scale_factors|.
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Select bitmap results from multiple favicons once
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // content::FaviconStatus supports multiple icon URLs.
222990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::FaviconID best_favicon_id = 0;
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapID> best_bitmap_ids;
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float highest_score = kSelectFaviconFramesInvalidScore;
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &bitmap_id_sizes);
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build vector of gfx::Size from |bitmap_id_sizes|.
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<gfx::Size> sizes;
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizes.push_back(bitmap_id_sizes[j].pixel_size);
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<size_t> candidate_bitmap_indices;
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score = 0;
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFaviconFrameIndices(sizes,
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_scale_factors,
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_size_in_dip,
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &candidate_bitmap_indices,
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &score);
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (score > highest_score) {
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      highest_score = score;
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_favicon_id = candidate_favicon_ids[i],
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_bitmap_ids.clear();
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_t candidate_index = candidate_bitmap_indices[j];
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        best_bitmap_ids.push_back(
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bitmap_id_sizes[candidate_index].bitmap_id);
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct FaviconBitmapResults from |best_favicon_id| and
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |best_bitmap_ids|.
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
226490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::IconType icon_type;
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       &icon_type)) {
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time last_updated;
227290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconBitmapResult bitmap_result;
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_url = icon_url;
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_type = icon_type;
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &last_updated,
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.bitmap_data,
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.pixel_size)) {
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.expired = (Time::Now() - last_updated) >
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromDays(kFaviconRefetchDays);
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bitmap_result.is_valid())
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
229290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
229390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconID>& icon_ids) {
2294b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find all the pages whose favicons we should set, we want to set it for
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the pages in the redirect chain if it redirected.
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirects;
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirects);
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save page <-> favicon associations.
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (history::RedirectList::const_iterator i(redirects.begin());
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != redirects.end(); ++i) {
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPage(
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
231490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
231590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconID>& icon_ids) {
23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two icon types are considered 'equivalent' if one of the icon types is
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
23245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any favicons which are orphaned as a result of the removal of the
23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon mappings.
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
232990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> unmapped_icon_ids = icon_ids;
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
23335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
233690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconID>::iterator icon_id_it = std::find(
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the icon mapping already exists, avoid removing it and adding it back.
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_id_it != unmapped_icon_ids.end()) {
23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unmapped_icon_ids.erase(icon_id_it);
23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
234590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if ((icon_type == chrome::TOUCH_ICON &&
234690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         m->icon_type == chrome::TOUCH_PRECOMPOSED_ICON) ||
234790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        (icon_type == chrome::TOUCH_PRECOMPOSED_ICON &&
234890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         m->icon_type == chrome::TOUCH_ICON) || (icon_type == m->icon_type)) {
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->DeleteIconMapping(m->mapping_id);
23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removing the icon mapping may have orphaned the associated favicon so
23525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we must recheck it. This is not super fast, but this case will get
23535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered rarely, since normally a page will always map to the same
23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // favicon IDs. It will mostly happen for favicons we import.
23555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!thumbnail_db_->HasMappingFor(m->icon_id))
23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->DeleteFavicon(m->icon_id);
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappings_changed = true;
23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed = true;
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetCachedRecentRedirects(
23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirect_list) {
23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *redirect_list = iter->second;
23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The redirect chain should have the destination URL as the last item.
23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirect_list->empty());
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirect_list->back() == page_url);
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No known redirects, construct mock redirect chain containing |page_url|.
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirect_list->push_back(page_url);
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirect_list;
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirect_list);
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
238990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FaviconChangedDetails* changed_details = new FaviconChangedDetails;
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirect_list.size(); ++i)
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.insert(redirect_list[i]);
23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         changed_details);
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Commit() {
2398b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that a commit may not actually have been scheduled if a caller
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly calls this instead of using ScheduleCommit. Likewise, we
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may reset the flag written by a pending commit. But this is OK! It
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will merely cause extra commits (which is kind of the idea). We
24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could optimize more for this case (we may get two extra commits in
24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some cases) but it hasn't been important yet.
24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2413b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Somebody left a transaction open";
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2420b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleCommit() {
2427868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get())
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduled_commit_ = new CommitLaterTask(this);
243090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CancelScheduledCommit() {
2437868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get()) {
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_->Cancel();
24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_ = NULL;
24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTaskImpl() {
2444b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // db went away, release all the refs.
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReleaseDBTasks();
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any canceled tasks.
24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.front()->Release();
24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.pop_front();
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_task_requests_.empty())
24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the first task.
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryDBTaskRequest* request = db_task_requests_.front();
24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.pop_front();
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->value->RunOnDBThread(this, db_.get())) {
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The task is done. Notify the callback.
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult();
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We AddRef'd the request before adding, need to release it now.
24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->Release();
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tasks wants to run some more. Schedule it at the end of current tasks.
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.push_back(request);
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // And process it after an invoke later.
247090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ReleaseDBTasks() {
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::list<HistoryDBTaskRequest*>::iterator i =
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*i)->Release();
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.clear();
24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generic operations
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURLs(urls);
24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURL(const GURL& url) {
24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURL(url);
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ExpireHistoryBetween(
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& restrict_urls,
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time begin_time,
25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time end_time) {
251158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!db_)
251258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
251458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
251558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      restrict_urls.empty()) {
251658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Special case deleting all history so it can be faster and to reduce the
251758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // possibility of an information leak.
251858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DeleteAllHistory();
251958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
252058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Clearing parts of history, have the expirer do the depend
252158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
252258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
252358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Force a commit, if the user is deleting something for privacy reasons,
252458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // we want to get it on disk ASAP.
252558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Commit();
25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin_time <= first_recorded_time_)
25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
25302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
25312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistoryForTimes(
25332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<base::Time>& times,
25342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time, base::Time end_time) {
2535b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (times.empty() || !db_)
25362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
25372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.begin() >= begin_time)
25392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Min time is before begin time: "
25402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
25412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.rbegin() < end_time)
25422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Max time is after end time: "
25432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
25442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::QueryOptions options;
25462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.begin_time = begin_time;
25472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.end_time = end_time;
25482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
25492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryResults results;
25502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryHistoryBasic(db_.get(), db_.get(), options, &results);
25512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1st pass: find URLs that are visited at one of |times|.
25532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<GURL> urls;
25542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
25552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (times.count(results[i].visit_time()) > 0)
25562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      urls.insert(results[i].url());
25572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
25582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (urls.empty())
25592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
25602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2nd pass: collect all visit times of those URLs.
25622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Time> times_to_expire;
25632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
25642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (urls.count(results[i].url()))
25652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.push_back(results[i].visit_time());
25662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
25672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put the times in reverse chronological order and remove
25692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // duplicates (for expirer_.ExpireHistoryForTimes()).
25702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::sort(times_to_expire.begin(), times_to_expire.end(),
25712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            std::greater<base::Time>());
25722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  times_to_expire.erase(
25732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::unique(times_to_expire.begin(), times_to_expire.end()),
25742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.end());
25752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expires by times and commit.
25772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!times_to_expire.empty());
25782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expirer_.ExpireHistoryForTimes(times_to_expire);
25792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Commit();
25802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(times_to_expire.back() >= first_recorded_time_);
25822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update |first_recorded_time_| if we expired it.
25832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (times_to_expire.back() == first_recorded_time_)
25842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
25852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistory(
25882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2589b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
25902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_first_recorded_time = false;
25912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
25932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         expire_list.begin(); it != expire_list.end(); ++it) {
25942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->begin_time < first_recorded_time_)
25972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        update_first_recorded_time = true;
25982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
25992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Commit();
26002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update |first_recorded_time_| if any deletion might have affected it.
26022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (update_first_recorded_time)
26032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_->GetStartDate(&first_recorded_time_);
26042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
26055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2608b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
26095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow url_row;
26135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(*i, &url_row))
26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // The URL isn't in the db; nothing to do.
26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector visits;
26175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetVisitsForURL(url_row.id(), &visits);
26185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visits.empty())
26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
26257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
26267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scheduled_kill_db_ = true;
26277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Don't just do the close/delete here, as we are being called by |db| and
26287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that seems dangerous.
26297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // TODO(shess): Consider changing KillHistoryDatabase() to use
26307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // RazeAndClose().  Then it can be cleared immediately.
26317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
26327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        FROM_HERE,
26337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::Bind(&HistoryBackend::KillHistoryDatabase, this));
26347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
26357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
26367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::KillHistoryDatabase() {
26387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scheduled_kill_db_ = false;
2639b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
26405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rollback transaction because Raze() cannot be called from within a
26435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
26445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RollbackTransaction();
26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = db_->Raze();
26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
26515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expirer keeps tabs on the active databases. Tell it about the
26545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // databases which will be closed.
2655bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  expirer_.SetDatabases(NULL, NULL, NULL);
26565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
26595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
26605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTask(
26635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<HistoryDBTaskRequest> request) {
2664868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(request.get());
26655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool task_scheduled = !db_task_requests_.empty();
26695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we up the refcount of the request. ProcessDBTaskImpl will
26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release when done with the task.
26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->AddRef();
26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.push_back(request.get());
26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!task_scheduled) {
26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No other tasks are scheduled. Process request now.
26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessDBTaskImpl();
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::BroadcastNotifications(
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDetails* details_deleted) {
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2683b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // HistoryService -> HistoryBackend::Closing().
2684b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->BroadcastNotifications(type, details_deleted);
26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete details_deleted;
26885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2690b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2691b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           bool archived,
2692b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           URLRows* rows) {
2693b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
2694b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsDeleted(all_history, archived, rows);
2695b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
2696b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
26975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deleting --------------------------------------------------------------------
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllHistory() {
27005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our approach to deleting all history is:
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  1. Copy the bookmarks and their dependencies to new tables with temporary
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     names.
27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  2. Delete the original tables. Since tables can not share pages, we know
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     that any data we don't want to keep is now in an unused page.
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  3. Renaming the temporary tables to match the original.
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  4. Vacuuming the database to delete the unused pages.
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we are likely to have very few bookmarks and their dependencies
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compared to all history, this is also much faster than just deleting from
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original tables directly.
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bookmarked URLs.
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BookmarkService::URLAndTitle> starred_urls;
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkService* bookmark_service = GetBookmarkService();
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service)
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->GetBookmarks(&starred_urls);
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRows kept_urls;
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < starred_urls.size(); i++) {
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(starred_urls[i].url, &row))
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear the last visit time so when we write these rows they are "clean."
27255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_last_visit(Time());
27265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_visit_count(0);
27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_typed_count(0);
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kept_urls.push_back(row);
27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear thumbnail and favicon history. The favicons for the given URLs will
27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be kept.
27333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClearAllThumbnailHistory(kept_urls)) {
27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Thumbnail history could not be cleared";
27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We continue in this error case. If the user wants to delete their
27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // history, we should delete as much as we can.
27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
273958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
274058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Therefore, we clear the list afterwards to make sure nobody uses this
274158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // invalid data.
27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllMainHistory(kept_urls))
27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Main history could not be cleared";
27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kept_urls.clear();
27455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2746bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete archived history.
2747b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Close the database and delete the file.
27495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
27502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath archived_file_name = GetArchivedFileName();
2751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(archived_file_name);
27525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now re-initialize the database (which may fail).
27545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset(new ArchivedDatabase());
27555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!archived_db_->Init(archived_file_name)) {
27565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Could not initialize the archived database.";
27575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_.reset();
27585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
27595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Open our long-running transaction on this database.
27605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_->BeginTransaction();
27615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
27625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
276658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Send out the notification that history is cleared. The in-memory database
27675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will pick this up and clear itself.
27685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLsDeletedDetails* details = new URLsDeletedDetails;
27695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->all_history = true;
2770b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NotifySyncURLsDeleted(true, false, NULL);
27715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, details);
27725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2775b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
27765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we have no reference to the thumbnail database, maybe there was an
27775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error opening it. In this case, we just try to blow it away to try to
27785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fix the error if it exists. This may fail, in which case either the
27795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file doesn't exist or there's no more we can do.
27803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sql::Connection::Delete(GetFaviconsFileName());
27813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
27823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Older version of the database.
2783eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(GetThumbnailFileName());
27845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
27855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Urls to retain mappings for.
27883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<GURL> urls_to_keep;
27893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin();
27903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != kept_urls.end(); ++i) {
27913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    urls_to_keep.push_back(i->url());
27923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
27935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Isolate from any long-running transaction.
27953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
27963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
27975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): If this fails, perhaps the database should be razed
27993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // or deleted.
28003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
28013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->RollbackTransaction();
28023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
28033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
28045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
28065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
28075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
28085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avaliable in HistoryBackend.
28095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->ClearAndroidURLRows();
28105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
28115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to remove all the pages associated with the dropped tables. There
28135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must be no transaction open on the table when we do this. We assume that
28145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our long-running transaction is open, so we complete it and start it again.
28155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thumbnail_db_->transaction_nesting() == 1);
28165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
28175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->Vacuum();
28185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
28195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
28205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
28235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the duplicate URL table. We will copy the kept URLs into this.
28245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CreateTemporaryURLTable())
28255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
282758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Insert the URLs into the temporary table.
28285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
28295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
283058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    db_->AddTemporaryURL(*i);
28315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the original URL table with the temporary one.
28345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CommitTemporaryURLTable())
28355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
28365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the old tables and recreate them empty.
28385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RecreateAllTablesButURL();
28395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to reclaim the space from the dropped tables. This must be done
28415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when there is no transaction open, and we assume that our long-running
28425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction is currently open.
28435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
28445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->Vacuum();
28455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
28465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
28475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
28495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkService* HistoryBackend::GetBookmarkService() {
28525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service_)
28535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->BlockTillLoaded();
28545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bookmark_service_;
28555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
28585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BriefVisitInfo info;
28595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.url_id = visit.url_id;
28605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.time = visit.visit_time;
28615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.transition = visit.transition;
28625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a delegate yet during setup or shutdown, we will drop
28635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these notifications.
2864b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
28655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->NotifyVisitDBObserversOnAddVisit(info);
28665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2868eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
2869eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::PopulateMostVisitedURLMap() {
2870eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MostVisitedURLList most_visited_urls;
2871eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
2872eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           &most_visited_urls);
2873eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2874eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2875eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2876eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    most_visited_urls_map_[most_visited_urls[i].url] = i;
2877eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2878eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2879eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2880eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2881eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2882eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2883eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rank = kPageVisitStatsMaxTopSites;
2884eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2885eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it != most_visited_urls_map_.end())
2886eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    rank = (*it).second;
2887eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2888eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            rank, kPageVisitStatsMaxTopSites + 1);
2889eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2890eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2891eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
28925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
2893