history_backend.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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"
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/favicon/favicon_changed_details.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/page_usage_data.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/common/importer/imported_favicon_usage.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_service.h"
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "components/favicon_base/select_favicon_frames.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/error_delegate_util.h"
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* The HistoryBackend consists of a number of components:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ArchivedDatabase (stores history older than 3 months)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (this does not store visit segments as they expire after 3 mos.)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExpireHistoryBackend (manages moving things from HistoryDatabase to
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          the ArchivedDatabase and deleting)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we keep segment data for in days. Currently 3 months.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This value needs to be greater or equal to
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dependency between MostVisitedModel and the history backend.
8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kSegmentDataRetention = 90;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kCommitIntervalSeconds = 10;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time before we re-fetch the favicon.
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kFaviconRefetchDays = 7;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleting some.
9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kMaxRedirectCount = 32;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and is archived.
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kArchiveDaysThreshold = 90;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The maximum number of top sites to track when recording top page visit stats.
9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const size_t kPageVisitStatsMaxTopSites = 50;
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts from PageUsageData to MostVisitedURL. |redirects| is a
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const RedirectList& redirects) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURL mv;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.url = page_data.GetURL();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.title = page_data.GetTitle();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (redirects.empty()) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirects must contain at least the target url.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects.push_back(mv.url);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects = redirects;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last url must be the target url.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mv.redirects.push_back(mv.url);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mv;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they are batched together. The important thing about this class is that
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be one of these commits still pending and holding a reference.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// task will still run (if we ever get to processing the event before
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown), but it will not do anything.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be assigned to a RunnableMethod.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in ExpireHistoryBackend).
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommitLaterTask(HistoryBackend* history_backend)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : history_backend_(history_backend) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The backend will call this function if it is being destroyed so that we
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release our reference.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_backend_ = NULL;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCommit() {
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (history_backend_.get())
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_backend_->Commit();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommitLaterTask() {}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HistoryBackend --------------------------------------------------------------
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Delegate* delegate,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkService* bookmark_service)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_dir_(history_dir),
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      scheduled_kill_db_(false),
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      expirer_(this, bookmark_service),
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recent_redirects_(kMaxRedirectCount),
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_destroy_message_loop_(NULL),
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_(false),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_service_(bookmark_service) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryBackend::~HistoryBackend() {
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReleaseDBTasks();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sql::Connection::Delete(GetAndroidCacheFileName());
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Init(const std::string& languages, bool force_fail) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force_fail)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitImpl(languages);
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delegate_->DBLoaded();
205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  memory_pressure_listener_.reset(new base::MemoryPressureListener(
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PopulateMostVisitedURLMap();
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const base::Closure& task) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null())
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_task_ = task;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Closing() {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any scheduled commit will have a reference to us, we must make it
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release that reference before we can be destroyed.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release our reference to the delegate, this reference will be keeping the
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // history service alive.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyRenderProcessHostDestruction(const void* host) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tracker_.NotifyRenderProcessHostDestruction(host);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetThumbnailFileName() const {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kThumbnailsFilename);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetFaviconsFileName() const {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kFaviconsFilename);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetArchivedFileName() const {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kArchivedHistoryFilename);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kAndroidCacheFilename);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is used to detect referrer loops.  Should not happen, but can
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the database is corrupt.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = from_visit;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (visit_id) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitRow row;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForVisit(visit_id, &row))
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row.segment_id)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return row.segment_id;  // Found a visit in this change with a segment.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the referrer of this visit, if any.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_id = row.referring_visit;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(visit_id) != visit_set.end()) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in referer chain, giving up";
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(visit_id);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::UpdateSegments(
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID from_visit,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID visit_id,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition_type,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time ts) {
283b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only consider main frames.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!content::PageTransitionIsMainFrame(transition_type))
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SegmentID segment_id = 0;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition t =
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition_type);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are we at the beginning of a new segment?
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that navigating to an existing entry (with back/forward) reuses the
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same transition type.  We are not adding it as a new segment in that case
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because if this was the target of a redirect, we might end up with
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2 entries for the same final URL. Ex: User types google.net, gets
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirected to google.com. A segment is created for google.net. On
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // google.com users navigates through a link, then press back. That last
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation is for the entry google.com transition typed. We end up adding
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a segment for that one as well. So we end up with google.net and google.com
30358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // in the segment table, showing as 2 entries in the NTP.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note also that we should still be updating the visit count for that segment
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which we are not doing now. It should be addressed when
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://crbug.com/96860 is fixed.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((t == content::PAGE_TRANSITION_TYPED ||
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If so, create or get the segment.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string segment_name = db_->ComputeSegmentName(url);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: if we update an existing segment, we update the url used to
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // represent that segment in order to minimize stale most visited
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // images.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: it is possible there is no segment ID set for this visit chain.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TYPED. (For example GENERATED). In this case this visit doesn't count
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // toward any segment.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = GetLastSegmentID(from_visit)))
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the segment in the visit.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->SetSegmentID(visit_id, segment_id)) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, increase the counter for that segment / day.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return segment_id;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateWithPageEndTime(const void* host,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int32 page_id,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const GURL& url,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Time end_ts) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = tracker_.GetLastVisit(host, page_id, url);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisitDuration(visit_id, end_ts);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
360b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the starting visit_time for visit_id.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_row;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetRowForVisit(visit_id, &visit_row)) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should never have a negative duration time even when time is skewed.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_row.visit_duration = end_ts > visit_row.visit_time ?
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateVisitRow(visit_row);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
374b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request.id_scope, request.page_id, request.referrer));
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID from_visit_id = last_ids.second;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a redirect chain is given, we expect the last item in that chain to be
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the final URL.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request.redirects.empty() ||
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         request.redirects.back() == request.url);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is adding older history, we need to make sure our times
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are correct.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request.time < first_recorded_time_)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = request.time;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition request_transition = request.transition;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition stripped_transition =
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransitionStripQualifier(request_transition);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_generated =
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is navigating to a not-previously-typed intranet hostname,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the transition to TYPED so that the omnibox will learn that this is
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a known host.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_redirects = request.redirects.size() > 1;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (content::PageTransitionIsMainFrame(request_transition) &&
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url(has_redirects ?
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request.redirects[0] : request.url);
408010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (origin_url.SchemeIs(url::kHttpScheme) ||
409010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        origin_url.SchemeIs(url::kHttpsScheme) ||
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        origin_url.SchemeIs(url::kFtpScheme)) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string host(origin_url.host());
412a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      size_t registry_length =
413a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          net::registry_controlled_domains::GetRegistryLength(
414a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              host,
415a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
416a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
417a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (registry_length == 0 && !db_->IsTypedHost(host)) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stripped_transition = content::PAGE_TRANSITION_TYPED;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition =
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::PageTransitionFromInt(
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                stripped_transition |
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                content::PageTransitionGetQualifier(request_transition));
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_redirects) {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The single entry is both a chain start and end.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition t = content::PageTransitionFromInt(
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition |
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START |
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_END);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect case (one element means just the page itself).
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_ids = AddPageVisit(request.url, request.time,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            last_ids.second, t, request.visit_source);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the segment for this visit. KEYWORD_GENERATED visits should not
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result in changing most visited, so we don't update segments (most
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // visited db).
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_keyword_generated) {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     request.time);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the referrer's duration.
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateVisitDuration(from_visit_id, request.time);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirect case. Add the redirect chain.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition redirect_info =
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects = request.redirects;
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (redirects[0].SchemeIs(content::kAboutScheme)) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the redirect source + referrer is "about" we skip it. This
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // happens when a page opens a new frame/window to about:blank and then
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // script sets the URL to somewhere else (used to hide the referrer). It
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would be nice to keep all these redirects properly but we don't ever
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // see the initial about:blank load, so we don't know where the
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // subsequent client redirect came from.
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this case, we just don't bother hooking up the source of the
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects, so we remove it.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirects.erase(redirects.begin());
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The first entry in the redirect chain initiated a client redirect.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't add this to the database since the referrer is already
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // there, so we skip over it but change the transition type of the first
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transition to client redirect.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The referrer is invalid when restoring a session that features an
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // https tab that redirects to a different host or to http. In this
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case we don't need to reconnect the new redirect with the existing
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // chain.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (request.referrer.is_valid()) {
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(request.referrer == redirects[0]);
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        redirects.erase(redirects.begin());
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the navigation entry for this visit has replaced that for the
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // first visit, remove the CHAIN_END marker from the first visit. This
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can be called a lot, for example, the page cycler, and most of the
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // time we won't have changed anything.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisitRow visit_row;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (request.did_replace_entry &&
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db_->GetRowForVisit(last_ids.second, &visit_row) &&
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          visit_row.transition = content::PageTransitionFromInt(
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->UpdateVisitRow(visit_row);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t redirect_index = 0; redirect_index < redirects.size();
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         redirect_index++) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransition t =
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::PageTransitionFromInt(stripped_transition | redirect_info);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If this is the last transition, add a CHAIN_END marker
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (redirect_index == (redirects.size() - 1)) {
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t = content::PageTransitionFromInt(
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            t | content::PAGE_TRANSITION_CHAIN_END);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Record all redirect visits with the same timestamp. We don't display
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them anyway, and if we ever decide to, we can reconstruct their order
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the redirect chain.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_ids = AddPageVisit(redirects[redirect_index],
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              request.time, last_ids.second,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              t, request.visit_source);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (t & content::PAGE_TRANSITION_CHAIN_START) {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the segment for this visit.
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateSegments(redirects[redirect_index],
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       from_visit_id, last_ids.second, t, request.time);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the visit_details for this visit.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateVisitDuration(from_visit_id, request.time);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Subsequent transitions in the redirect list must all be server
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects.
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last, save this redirect chain for later so we can set titles & favicons
528bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // on the redirected pages properly.
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recent_redirects_.Put(request.url, redirects);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the last visit to the tracker so we can get outgoing transitions.
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation anyway, so last_visit_id is always zero for them.  But adding
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them here confuses main frame history, so we skip them for now.
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tracker_.AddVisit(request.id_scope, request.page_id, request.url,
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      last_ids.second);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::InitImpl(const std::string& languages) {
550b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!db_) << "Initializing HistoryBackend twice";
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the rare case where the db fails to initialize a dialog may get shown
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the blocks the caller, yet allows other messages through. For this reason
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only set db_ to the created database if creation is successful. That
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way other methods won't do anything as db_ is still NULL.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
558bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Compute the file names.
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
5603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::FilePath thumbnail_name = GetFaviconsFileName();
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath archived_name = GetArchivedFileName();
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
563bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete the old index database files which are no longer used.
564bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DeleteFTSIndexDatabases();
565bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // History database.
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new HistoryDatabase());
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Unretained to avoid a ref loop with db_.
5707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  db_->set_error_callback(
5717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Bind(&HistoryBackend::DatabaseErrorCallback,
5727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                 base::Unretained(this)));
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  sql::InitStatus status = db_->Init(history_name);
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_OK:
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_FAILURE: {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A NULL db_ will cause all calls on this object to notice this error
5807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // and to not continue. If the error callback scheduled killing the
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database, the task it posted has not executed yet. Try killing the
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database now before we close it.
5837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      bool kill_db = scheduled_kill_db_;
5847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (kill_db)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        KillHistoryDatabase();
5867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
587a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->NotifyProfileError(status);
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the in-memory database and send it back to the history service on the
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // main thread.
597a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  {
598a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<InMemoryHistoryBackend> mem_backend(new InMemoryHistoryBackend);
599a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (mem_backend->Init(history_name, db_.get()))
600a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delegate_->SetInMemoryBackend(mem_backend.Pass());
601a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Thumbnail database.
6053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): "thumbnail database" these days only stores
6063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // favicons.  Thumbnails are stored in "top sites".  Consider
6073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // renaming "thumbnail" references to "favicons" or something of the
6083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // sort.
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_.reset(new ThumbnailDatabase());
6104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) {
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unlike the main database, we don't error out when the database is too
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new because this error is much less severe. Generally, this shouldn't
61358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // happen since the thumbnail and main database versions should be in sync.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We'll just continue without thumbnails & favicons in this case or any
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other error.
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the thumbnail database.";
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Archived database.
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->needs_version_17_migration()) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See needs_version_17_migration() decl for more. In this case, we want
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to delete the archived database and need to do so before we try to
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // open the file. We can ignore any error (maybe the file doesn't exist).
625eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(archived_name);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  archived_db_.reset(new ArchivedDatabase());
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!archived_db_->Init(archived_name)) {
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the archived database.";
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Generate the history and thumbnail database metrics only after performing
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any migration work.
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::RandInt(1, 100) == 50) {
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only do this computation sometimes since it can be expensive.
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->ComputeDatabaseMetrics(history_name);
6382385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (thumbnail_db_)
6392385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      thumbnail_db_->ComputeDatabaseMetrics();
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tell the expiration module about all the nice databases we made. This must
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // happen before db_->Init() is called since the callback ForceArchiveHistory
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may need to expire stuff.
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // *sigh*, this can all be cleaned up when that migration code is removed.
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The main DB initialization should intuitively be first (not that it
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // actually matters) and the expirer should be set last.
64968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  expirer_.SetDatabases(db_.get(), archived_db_.get(), thumbnail_db_.get());
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the long-running transaction.
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
653b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
655b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the first item in our database.
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start expiring old stuff.
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
665b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    android_provider_backend_.reset(new AndroidProviderBackend(
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetAndroidCacheFileName(), db_.get(), thumbnail_db_.get(),
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bookmark_service_, delegate_.get()));
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HISTOGRAM_TIMES("History.InitTime",
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  TimeTicks::Now() - beginning_time);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
676ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid HistoryBackend::OnMemoryPressure(
677ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
678ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool trim_aggressively = memory_pressure_level ==
679ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
680ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (db_)
681ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    db_->TrimMemory(trim_aggressively);
682ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (thumbnail_db_)
683ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    thumbnail_db_->TrimMemory(trim_aggressively);
684ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (archived_db_)
685ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    archived_db_->TrimMemory(trim_aggressively);
686ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
687ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloseAllDatabases() {
689b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the long-running transaction.
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->CommitTransaction();
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset();
69358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Forget the first recorded time since the database is closed.
69458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    first_recorded_time_ = base::Time();
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
696b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
700b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time time,
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID referring_visit,
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitSource visit_source) {
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Top-level frame navigations are visible, everything else is hidden
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool new_hidden = !content::PageTransitionIsMainFrame(transition);
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This code must stay in sync with
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExpireHistoryBackend::ExpireURLsForVisits().
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // typed, which would eliminate the need for this code.
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int typed_increment = 0;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition transition_type =
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition);
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((transition_type == content::PAGE_TRANSITION_TYPED &&
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !content::PageTransitionIsRedirect(transition)) ||
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typed_increment = 1;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
727eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
728eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Only count the page visit if it came from user browsing and only count it
729eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // once when cycling through a redirect chain.
730eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (visit_source == SOURCE_BROWSED &&
731eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
732eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordTopPageVisitStats(url);
733eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
734eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
735eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if this URL is already in the DB.
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update of an existing row.
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::PageTransitionStripQualifier(transition) !=
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_RELOAD)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_visit_count(url_info.visit_count() + 1);
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (typed_increment)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_typed_count(url_info.typed_count() + typed_increment);
746c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (url_info.last_visit() < time)
747c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_info.set_last_visit(time);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only allow un-hiding of pages, never hiding.
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_hidden)
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_hidden(false);
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateURLRow(url_id, url_info);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Addition of a new row.
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_visit_count(1);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_typed_count(typed_increment);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_last_visit(time);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_hidden(new_hidden);
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_id = db_->AddURL(url_info);
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Adding URL failed.";
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::make_pair(0, 0);
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.id_ = url_id;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the visit with the time to the database.
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyVisitObservers(visit_info);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_info.visit_time < first_recorded_time_)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = visit_info.visit_time;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification of the visit.
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id) {
779b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
780b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
781b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
782a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<URLVisitedDetails> details(new URLVisitedDetails);
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->transition = transition;
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->row = url_info;
785cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    details->visit_time = time;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // GetMostRecentRedirectsTo(url, &details->redirects);
789a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED,
790a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
801b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
8050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<URLsModifiedDetails> modified_in_archive(new URLsModifiedDetails);
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We will add to either the archived database or the main one depending on
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the date of the added visit.
8110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    URLDatabase* url_database = NULL;
8120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    VisitDatabase* visit_database = NULL;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit())) {
814b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      if (!archived_db_)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;  // No archived database to save it to, just forget this.
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = archived_db_.get();
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = archived_db_.get();
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = db_.get();
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = db_.get();
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = url_database->GetRowForURL(i->url(), &existing_url);
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_id = url_database->AddURL(*i);
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i->typed_count() > 0) {
8340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // Collect expired URLs that belong to |archived_db_| separately; we
8350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // want to fire NOTIFICATION_HISTORY_URLS_MODIFIED only for changes that
8360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // take place in the main |db_|.
8370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (url_database == db_.get()) {
8380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified->changed_urls.push_back(*i);
8390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified->changed_urls.back().set_id(url_id);  // i->id_ is likely 0.
8400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        } else {
8410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified_in_archive->changed_urls.push_back(*i);
8420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified_in_archive->changed_urls.back().set_id(url_id);
8430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          content::PageTransitionFromInt(
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_LINK |
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_START |
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_END), 0);
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!visit_database->AddVisit(&visit_info, visit_source)) {
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (typed_url_syncable_service_.get()) {
8670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    typed_url_syncable_service_->OnUrlsModified(
8680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        &modified_in_archive->changed_urls);
869b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
8700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
871b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
878a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         modified.PassAs<HistoryDetails>());
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return time < expirer_.GetCurrentArchiveTime();
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
887a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url,
888a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  const base::string16& title) {
889b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
925b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
926b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
928a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
934a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               const base::string16& title) {
935b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_info.set_title(base::UTF8ToUTF16(url.spec()));
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
95990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
961b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
976b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
982b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int max_visits,
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               VisitVector* visits) {
990b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
996b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->UpdateURLRow(id, url);
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::AddVisits(const GURL& url,
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<VisitInfo>& visits,
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               VisitSource visit_source) {
1004b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         visit != visits.end(); ++visit) {
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!AddPageVisit(
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              url, visit->first, 0, visit->second, visit_source).first) {
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1019b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.ExpireVisits(visits);
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VisitSourceMap* sources) {
1029b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetVisitsSource(visits, sources);
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1037b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetRowForURL(url, url_row) != 0;
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryURL(scoped_refptr<QueryURLRequest> request,
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const GURL& url,
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool want_visits) {
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow* row = &request->value.a;
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector* visits = &request->value.b;
1051b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetRowForURL(url, row)) {
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Have a row.
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = true;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Optionally query the visits.
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (want_visits)
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetVisitsForURL(row->id(), visits);
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, row, visits);
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1064b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1065b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return typed_url_syncable_service_.get();
1066b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1067b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Segment usage ---------------------------------------------------------------
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteOldSegmentData() {
1071b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->DeleteSegmentData(Time::Now() -
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           TimeDelta::FromDays(kSegmentDataRetention));
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QuerySegmentUsage(
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time from_time,
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_result_count) {
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1083b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this is the first time we query segments, invoke
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DeleteOldSegmentData asynchronously. We do this to cleanup old
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // entries.
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!segment_queried_) {
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_ = true;
109190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->PostTask(
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keyword visits --------------------------------------------------------------
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 TemplateURLID keyword_id,
1103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                 const base::string16& term) {
1104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the ID for this URL.
11080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  URLRow row;
11090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!db_->GetRowForURL(url, &row)) {
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a small possibility the url was deleted before the keyword
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was added. Ignore the request.
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  db_->SetKeywordSearchTermsForURL(row.id(), keyword_id, term);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(
11180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      scoped_ptr<HistoryDetails>(
11200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          new KeywordSearchUpdatedDetails(row, keyword_id, term)));
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllSearchTermsForKeyword(
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id) {
1126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->DeleteAllSearchTermsForKeyword(keyword_id);
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky): bug 1168470. Need to move from archive dbs too.
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetMostRecentKeywordSearchTerms(
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id,
1137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& prefix,
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_count) {
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &(request->value));
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void HistoryBackend::DeleteKeywordSearchTermForURL(const GURL& url) {
11500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!db_)
11510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, NULL);
11540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!url_id)
11550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  db_->DeleteKeywordSearchTermForURL(url_id);
11570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  BroadcastNotifications(
11590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
11600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_ptr<HistoryDetails>(new KeywordSearchDeletedDetails(url_id)));
11610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScheduleCommit();
11620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
11630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HistoryBackend::DeleteMatchingURLsForKeyword(TemplateURLID keyword_id,
11655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  const base::string16& term) {
11665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_)
11675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
11685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<KeywordSearchTermRow> rows;
11705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_->GetKeywordSearchTermRows(term, &rows)) {
11715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<GURL> items_to_delete;
11725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLRow row;
11735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (std::vector<KeywordSearchTermRow>::iterator it = rows.begin();
11745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it != rows.end(); ++it) {
11755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if ((it->keyword_id == keyword_id) && db_->GetURLRow(it->url_id, &row))
11765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        items_to_delete.push_back(row.url());
11775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
11785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DeleteURLs(items_to_delete);
11795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
11805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
11815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Downloads -------------------------------------------------------------------
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)uint32 HistoryBackend::GetNextDownloadId() {
1185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return db_ ? db_->GetNextDownloadId() : content::DownloadItem::kInvalidId;
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get all the download entries from the database.
11892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1190b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QueryDownloads(rows);
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update a particular download entry.
11952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->UpdateDownload(data);
11992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HistoryBackend::CreateDownload(const history::DownloadRow& history_info) {
1203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
1204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
1205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool success = db_->CreateDownload(history_info);
12062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
1207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return success;
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_before = db_->CountDownloads();
12142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks started_removing = base::TimeTicks::Now();
12152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HistoryBackend uses a long-running Transaction that is committed
12162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // periodically, so this loop doesn't actually hit the disk too hard.
12177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::set<uint32>::const_iterator it = ids.begin();
12187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       it != ids.end(); ++it) {
12192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->RemoveDownload(*it);
12202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScheduleCommit();
12222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks finished_removing = base::TimeTicks::Now();
12237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_after = db_->CountDownloads();
12247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
12257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_LE(downloads_count_after, downloads_count_before);
12267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (downloads_count_after > downloads_count_before)
12277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
12297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
12307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        num_downloads_deleted);
12317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeDelta micros = (1000 * (finished_removing - started_removing));
12327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
12337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (num_downloads_deleted > 0) {
12347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
12357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        (1000 * micros) / num_downloads_deleted);
12362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GE(ids.size(), num_downloads_deleted);
12387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (ids.size() < num_downloads_deleted)
12397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
12417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        ids.size() - num_downloads_deleted);
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
1245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  const base::string16& text_query,
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const QueryOptions& options) {
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1252b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (text_query.empty()) {
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Basic history query for the main database.
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Now query the archived database. This is a bit tricky because we don't
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // want to query it if the queried time range isn't going to find anything
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // in it.
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(brettw) bug 1171036: do blimpie querying for the archived database
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // as well.
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if (archived_db_.get() &&
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Text history query.
1266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      QueryHistoryText(db_.get(), db_.get(), text_query, options,
1267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                       &request->value);
1268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (archived_db_.get() &&
1269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          expirer_.GetCurrentArchiveTime() >= options.begin_time) {
1270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        QueryHistoryText(archived_db_.get(), archived_db_.get(), text_query,
1271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         options, &request->value);
1272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.QueryHistory",
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic time-based querying of history.
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       VisitDatabase* visit_db,
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const QueryOptions& options,
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QueryResults* result) {
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First get all visits.
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
12892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits);
12902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add them and the URL rows to the results.
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); i++) {
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VisitRow visit = visits[i];
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add a result row for this visit, get the URL info from the DB.
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_db->GetURLRow(visit.url_id, &url_result)) {
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to get id " << visit.url_id
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " from history.urls.";
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // DB out of sync and URL doesn't exist, try to recover.
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid()) {
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Got invalid URL from history.urls with id "
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << visit.url_id << ":  "
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << url_result.url().possibly_invalid_spec();
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The archived database may be out of sync with respect to starring,
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // titles, last visit date, etc. Therefore, we query the main DB if the
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // current URL database is not the main one.
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url_db == db_.get()) {
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Currently querying the archived DB, update with the main database to
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // catch any interesting stuff. This will update it if it exists in the
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // main DB, and do nothing otherwise.
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetRowForURL(url_result.url(), &url_result);
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(visit.visit_time);
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Set whether the visit was blocked for a managed user by looking at the
1324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // transition type.
1325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url_result.set_blocked_visit(
1326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't set any of the query-specific parts of the URLResult, since
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // snippets and stuff don't apply to basic querying.
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_more_results && options.begin_time <= first_recorded_time_)
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Text-based querying of history.
1338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::QueryHistoryText(URLDatabase* url_db,
1339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      VisitDatabase* visit_db,
1340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      const base::string16& text_query,
1341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const QueryOptions& options,
1342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      QueryResults* result) {
1343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  URLRows text_matches;
1344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  url_db->GetTextMatches(text_query, &text_matches);
1345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<URLResult> matching_visits;
1347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VisitVector visits;    // Declare outside loop to prevent re-construction.
1348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < text_matches.size(); i++) {
1349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const URLRow& text_match = text_matches[i];
1350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Get all visits for given URL match.
13514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    visit_db->GetVisibleVisitsForURL(text_match.id(), options, &visits);
1352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < visits.size(); j++) {
1353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      URLResult url_result(text_match);
1354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_result.set_visit_time(visits[j].visit_time);
1355eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      matching_visits.push_back(url_result);
1356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::sort(matching_visits.begin(), matching_visits.end(),
1360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            URLResult::CompareVisitTime);
1361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t max_results = options.max_count == 0 ?
1363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (std::vector<URLResult>::iterator it = matching_visits.begin();
1365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != matching_visits.end() && result->size() < max_results; ++it) {
1366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->AppendURLBySwapping(&(*it));
1367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (matching_visits.size() == result->size() &&
1370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      options.begin_time <= first_recorded_time_)
1371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->set_reached_beginning(true);
1372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Frontend to GetMostRecentRedirectsFrom from the history thread.
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsFrom(
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsFrom(url, &request->value);
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsTo(
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsTo(url, &request->value);
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetVisibleVisitCountToHost(
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetVisibleVisitCountToHostRequest> request,
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time first_visit;
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool success = db_.get() &&
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, count, first_visit);
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryTopURLsAndRedirects(
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count) {
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1411b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), false, NULL, NULL);
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL>* top_urls = &request->value.a;
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectMap* redirects = &request->value.b;
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_count, &data.get());
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_urls->push_back(data[i]->GetURL());
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*redirects)[top_urls->back()] = list;
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), true, top_urls, redirects);
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Will replace QueryTopURLsAndRedirectsRequest.
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLs(
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryMostVisitedURLsRequest> request,
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count,
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int days_back) {
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1441b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), MostVisitedURLList());
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURLList* result = &request->value;
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  QueryMostVisitedURLsImpl(result_count, days_back, result);
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), *result);
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryFilteredURLs(
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<QueryFilteredURLsRequest> request,
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int result_count,
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const history::VisitFilter& filter,
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool extended_info)  {
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time request_start = base::Time::Now();
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1462b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), FilteredURLList());
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, double> score_map;
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); ++i) {
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(georgey): experiment with visit_segment database granularity (it is
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently 24 hours) to use it directly instead of using visits database,
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is considerably slower.
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.reserve(score_map.size());
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<URLID, double>::iterator it = score_map.begin();
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != score_map.end(); ++it) {
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* pud = new PageUsageData(it->first);
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pud->SetScore(it->second);
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.push_back(pud);
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit to the top |result_count| results.
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
14902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_count && implicit_cast<int>(data.size()) > result_count)
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.resize(result_count);
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow info;
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetURLRow(data[i]->GetID(), &info)) {
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetURL(info.url());
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetTitle(info.title());
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilteredURLList& result = request->value;
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilteredURL url(*current_data);
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extended_info) {
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitVector visits;
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisitsForURL(current_data->GetID(), &visits);
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits.size() > 0) {
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url.extended_info.total_visits = visits.size();
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < visits.size(); ++i) {
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url.extended_info.duration_opened +=
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visits[i].visit_duration.InSeconds();
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (visits[i].visit_time > url.extended_info.last_visit_time) {
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url.extended_info.last_visit_time = visits[i].visit_time;
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(macourteau): implement the url.extended_info.visits stat.
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.push_back(url);
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta_time = std::max(1, std::min(999,
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATIC_HISTOGRAM_POINTER_BLOCK(
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NewTabPage.SuggestedSitesLoadTime",
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Add(delta_time),
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), result);
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              int days_back,
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              MostVisitedURLList* result) {
1538b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() -
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromDays(days_back),
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         result_count, &data.get());
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects;
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back(url);
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsFromSpecificVisit(
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit, history::RedirectList* redirects) {
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow any redirects from the given visit and add them to the list.
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It *should* be impossible to get a circular chain here, but we check
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just in case to avoid infinite loops.
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsToSpecificVisit(
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit,
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow redirects going to cur_visit. These are added to |redirects| in
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the order they are found. If a redirect chain looks like A -> B -> C and
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |cur_visit| = C, redirects will be {B, A} in that order.
1579b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsFrom(
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& from_url,
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1599b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsFromSpecificVisit(cur_visit, redirects);
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsTo(
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& to_url,
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1615b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsToSpecificVisit(cur_visit, redirects);
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          HistoryURLProviderParams* params) {
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExecuteWithDB should handle the NULL database case.
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->ExecuteWithDB(this, db_.get(), params);
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1633bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid HistoryBackend::DeleteFTSIndexDatabases() {
1634bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Find files on disk matching the text databases file pattern so we can
1635bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // quickly test for and delete them.
1636bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath::StringType filepattern =
1637bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FILE_PATH_LITERAL("History Index *");
1638bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FileEnumerator enumerator(
1639bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      history_dir_, false, base::FileEnumerator::FILES, filepattern);
1640bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  int num_databases_deleted = 0;
1641bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath current_file;
1642bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  while (!(current_file = enumerator.Next()).empty()) {
1643bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (sql::Connection::Delete(current_file))
1644bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      num_databases_deleted++;
1645bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1646bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1647bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                       num_databases_deleted);
1648bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
1649bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFavicons(
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
16542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
16550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
16562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types,
16572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
16582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void HistoryBackend::GetLargestFaviconForURL(
16620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const GURL& page_url,
16630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<int>& icon_types,
16640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int minimum_size_in_pixels,
16650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconBitmapResult* favicon_bitmap_result) {
16668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(favicon_bitmap_result);
16678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
16698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
16708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
16728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
16748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
16758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      icon_mappings.empty())
16768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
16778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int required_icon_types = 0;
16798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator i = icon_types.begin();
16808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_types.end(); ++i) {
16818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    required_icon_types |= *i;
16828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
16838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find the largest bitmap for each IconType placing in
16858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // |largest_favicon_bitmaps|.
16860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::map<favicon_base::IconType, FaviconBitmap> largest_favicon_bitmaps;
16878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
16888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_mappings.end(); ++i) {
16898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!(i->icon_type & required_icon_types))
16908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      continue;
16918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
16928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
16938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
16948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (std::vector<FaviconBitmapIDSize>::const_iterator j =
16958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)             bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
16968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (largest.bitmap_id == 0 ||
16978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest.pixel_size.width() < j->pixel_size.width() &&
16988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           largest.pixel_size.height() < j->pixel_size.height())) {
16998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.icon_id = i->icon_id;
17008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.bitmap_id = j->bitmap_id;
17018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.pixel_size = j->pixel_size;
17028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
17038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
17048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (largest_favicon_bitmaps.empty())
17068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
17078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find an icon which is larger than minimum_size_in_pixels in the order of
17098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // icon_types.
17108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FaviconBitmap largest_icon;
17118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator t = icon_types.begin();
17128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       t != icon_types.end(); ++t) {
17130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (std::map<favicon_base::IconType, FaviconBitmap>::const_iterator f =
17140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             largest_favicon_bitmaps.begin();
17150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         f != largest_favicon_bitmaps.end();
17160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++f) {
17178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (f->first & *t &&
17188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest_icon.bitmap_id == 0 ||
17198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
17208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
17218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon = f->second;
17228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
17238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
17248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
17258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon.pixel_size.height() > minimum_size_in_pixels)
17268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
17278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  GURL icon_url;
17300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
17318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
17328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &icon_type)) {
17338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
17348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::Time last_updated;
17370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconBitmapResult bitmap_result;
17388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_url = icon_url;
17398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_type = icon_type;
17408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
17418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &last_updated,
17428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.bitmap_data,
17438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.pixel_size)) {
17448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
17458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.expired = (Time::Now() - last_updated) >
17488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      TimeDelta::FromDays(kFaviconRefetchDays);
17498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (bitmap_result.is_valid())
17508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    *favicon_bitmap_result = bitmap_result;
17518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
17538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                  TimeTicks::Now() - beginning_time);
17548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
17558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFaviconsForURL(
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
17602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
17610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
17622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_results);
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconsFromDB(page_url, icon_types, desired_size_in_dip,
17642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    desired_scale_factors, bitmap_results);
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetFaviconForID(
17680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id,
17692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int desired_size_in_dip,
17702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ScaleFactor desired_scale_factor,
17710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
17720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_ids.push_back(favicon_id);
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::ScaleFactor> desired_scale_factors;
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desired_scale_factors.push_back(desired_scale_factor);
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get results from DB.
17782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids,
17792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_size_in_dip,
17802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_scale_factors,
17812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bitmap_results);
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetch(
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
17892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
17900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
17912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
17922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
17932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MergeFavicon(
17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url,
17990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
1802b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID favicon_id =
180690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!favicon_id) {
18092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is no favicon at |icon_url|, create it.
1810eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
18112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
18142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
18172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // replace it.
18182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bitmap_identical = false;
18192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool replaced_bitmap = false;
18202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
18212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
18222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
18232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
18242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
18252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bitmap_identical = true;
18262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
18272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
18282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_data, base::Time::Now());
18292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        replaced_bitmap = true;
18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
18312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a vector of the pixel sizes of the favicon bitmaps currently at
18362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url|.
18372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
18382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
18392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!replaced_bitmap && !bitmap_identical) {
18422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
18432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmaps are not consistent with the merged in data.
18442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delete an arbitrary favicon bitmap to avoid going over the limit of
18472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |kMaxFaviconBitmapsPerIconURL|.
18482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
18492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
18502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.erase(favicon_sizes.begin());
18512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
18532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    pixel_size);
18542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(pixel_size);
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A site may have changed the favicons that it uses for |page_url|.
18582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Example Scenario:
18592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   page_url = news.google.com
186058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //   Initial State: www.google.com/favicon.ico 16x16, 32x32
18612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
18622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //                ..., 16x16)
18632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulties:
18652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1. Sync requires that a call to GetFaviconsForURL() returns the
18662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    |bitmap_data| passed into MergeFavicon().
18672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
18682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      stay mapped to news.google.com because it would be unclear which 16x16
18692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      bitmap should be returned via GetFaviconsForURL().
18702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2. www.google.com/favicon.ico may be mapped to more than just
18722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    news.google.com (eg www.google.com).
18732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
18742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To resolve these problems, we copy all of the favicon bitmaps previously
18762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mapped to news.google.com (|page_url|) and add them to the favicon at
18772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
18782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url| are set to default to indicate that |icon_url| has incomplete
18792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // / incorrect data.
188058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
18812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //              news.google.com
18822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
18832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //               modified.
18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
18862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
18892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
18902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i) {
18912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
18922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (icon_mappings[i].icon_url == icon_url)
18952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmap> bitmaps_to_copy;
18982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
18992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     &bitmaps_to_copy);
19002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
19012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Do not add a favicon bitmap at a pixel size for which there is already
19022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // a favicon bitmap mapped to |icon_url|. The one there is more correct
19032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // and having multiple equally sized favicon bitmaps for |page_url| is
19042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ambiguous in terms of GetFaviconsForURL().
19052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
19062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
19072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != favicon_sizes.end())
19082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
19092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add the favicon bitmap as expired as it is not consistent with the
19112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // merged in data.
19122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->AddFaviconBitmap(favicon_id,
19132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].bitmap_data, base::Time(),
19142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].pixel_size);
19152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
19162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
19182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
19192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
19202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the favicon mappings such that only |icon_url| is mapped to
19232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |page_url|.
19242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool mapping_changed = false;
19252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
19260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID> favicon_ids;
19272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_ids.push_back(favicon_id);
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
19292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mapping_changed = true;
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (mapping_changed || !bitmap_identical)
19332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFavicons(
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
19390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
19400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapData>& favicon_bitmap_data) {
1941b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build map of FaviconBitmapData for each icon url.
19470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef std::map<GURL, std::vector<favicon_base::FaviconBitmapData> >
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BitmapDataByIconURL;
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitmapDataByIconURL grouped_by_icon_url;
19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track whether the method modifies or creates any favicon bitmaps, favicons
19562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // or icon mappings.
19572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool data_modified = false;
19582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> icon_ids;
19602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
19612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != grouped_by_icon_url.end(); ++it) {
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = it->first;
19630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id =
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
19652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!icon_id) {
19672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Remove the favicon sizes attribute from
19682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ThumbnailDatabase::AddFavicon().
1969eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
19702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_modified = true;
19712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_ids.push_back(icon_id);
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!data_modified)
19752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, &data_modified);
19762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
19772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, NULL);
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_modified |=
19812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_modified) {
19842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Send notification to the UI as an icon mapping, favicon, or favicon
19852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmap was changed by this function.
19862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
19872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1994b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ ||
19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &icon_mappings))
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloneFavicons(const GURL& old_page_url,
20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& new_page_url) {
2008b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent cross-domain cloning.
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetImportedFavicons(
20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ImportedFaviconUsage>& favicon_usage) {
2021b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Track all URLs that had their favicons set or updated.
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> favicons_changed;
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_usage.size(); i++) {
20300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id =
20310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        thumbnail_db_->GetFaviconIDForFaviconURL(
20320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            favicon_usage[i].favicon_url, favicon_base::FAVICON, NULL);
20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_id) {
20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This favicon doesn't exist yet, so we create it using the given data.
20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkotwicz): Pass in real pixel size.
20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_id = thumbnail_db_->AddFavicon(
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_usage[i].favicon_url,
20380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          favicon_base::FAVICON,
20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new base::RefCountedBytes(favicon_usage[i].png_data),
20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          now,
20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::Size());
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the mapping from all the URLs to the favicon.
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkService* bookmark_service = GetBookmarkService();
20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url != favicon_usage[i].urls.end(); ++url) {
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow url_row;
20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!db_->GetRowForURL(*url, &url_row)) {
20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the URL is present as a bookmark, add the url in history to
20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // save the favicon mapping. This will match with what history db does
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for regular bookmarked URLs with favicons - when history db is
20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // cleaned, we keep an entry in the db with 0 visits as long as that
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // url is bookmarked.
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (bookmark_service && bookmark_service_->IsBookmarked(*url)) {
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          URLRow url_info(*url);
20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_visit_count(0);
20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_typed_count(0);
20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_last_visit(base::Time());
20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_hidden(false);
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->AddURL(url_info);
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
206690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!thumbnail_db_->GetIconMappingsForPageURL(
20670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                *url, favicon_base::FAVICON, NULL)) {
20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // URL is present in history, update the favicon *only* if it is not
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // set already.
20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!favicons_changed.empty()) {
20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the notification about the changed favicon URLs.
2079a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<FaviconChangedDetails> changed_details(
2080a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new FaviconChangedDetails);
20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.swap(favicons_changed);
20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2083a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           changed_details.PassAs<HistoryDetails>());
20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* page_url,
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
20922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
20930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |page_url| is specified, |icon_types| must be either a single icon
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type or icon types which are equivalent.
20960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!page_url || icon_types == favicon_base::FAVICON ||
20970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_ICON ||
20980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_PRECOMPOSED_ICON ||
20990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types ==
21000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             (favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON));
21012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bitmap_results->clear();
21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The icon type for which the mappings will the updated and data will be
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned.
21110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType selected_icon_type = favicon_base::INVALID_ICON;
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_urls.size(); ++i) {
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = icon_urls[i];
21150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type_out;
21160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const favicon_base::FaviconID favicon_id =
211790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(
211890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            icon_url, icon_types, &icon_type_out);
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_id) {
21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Return and update icon mappings only for the largest icon type. As
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if an |icon_url| with a larger icon type is found.
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out > selected_icon_type) {
21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_icon_type = icon_type_out;
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.clear();
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out == selected_icon_type)
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.push_back(favicon_id);
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_url && !favicon_ids.empty()) {
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool mappings_updated =
21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              favicon_ids);
21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappings_updated) {
21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommit();
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_size_in_dip,
21442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_scale_factors, bitmap_results);
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconBitmaps(
21480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id,
21490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapData>& favicon_bitmap_data,
21502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* favicon_bitmaps_changed) {
21512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_bitmaps_changed)
21522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *favicon_bitmaps_changed = false;
21532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconBitmapData> to_add = favicon_bitmap_data;
21582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
21602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
21610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapData>::iterator match_it =
21620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        to_add.end();
21630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (std::vector<favicon_base::FaviconBitmapData>::iterator it =
21640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             to_add.begin();
21650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         it != to_add.end();
21660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++it) {
21672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->pixel_size == pixel_size) {
21682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        match_it = it;
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
21742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (match_it == to_add.end()) {
21752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
21762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed)
21782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *favicon_bitmaps_changed = true;
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
21802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed &&
21812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !*favicon_bitmaps_changed &&
21822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
21832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
21842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id, base::Time::Now());
21852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
21862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
21872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Time::Now());
21882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (favicon_bitmaps_changed)
21902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *favicon_bitmaps_changed = true;
21912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
21922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      to_add.erase(match_it);
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < to_add.size(); ++i) {
21972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
21982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time::Now(), to_add[i].pixel_size);
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_bitmaps_changed)
22012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *favicon_bitmaps_changed = true;
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool HistoryBackend::ValidateSetFaviconsParams(const std::vector<
22060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconBitmapData>& favicon_bitmap_data) const {
22072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<GURL, size_t> BitmapsPerIconURL;
22082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BitmapsPerIconURL num_bitmaps_per_icon_url;
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!favicon_bitmap_data[i].bitmap_data.get())
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
22142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!num_bitmaps_per_icon_url.count(icon_url))
22152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_bitmaps_per_icon_url[icon_url] = 1u;
22162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
22172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++num_bitmaps_per_icon_url[icon_url];
22182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
22192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
22202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
22212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
22242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != num_bitmaps_per_icon_url.end(); ++it) {
22252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->second > kMaxFaviconBitmapsPerIconURL)
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::IsFaviconBitmapDataEqual(
22322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
22332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!new_bitmap_data.get())
22352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
22382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmap(bitmap_id,
22392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL,
22402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  &original_bitmap_data,
22412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL);
22422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_bitmap_data->Equals(original_bitmap_data);
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconsFromDB(
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
22500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* favicon_bitmap_results) {
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(favicon_bitmap_results);
22522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_bitmap_results->clear();
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2254b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Time the query.
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get FaviconIDs for |page_url| and one of |icon_types|.
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &icon_mappings);
22640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i)
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ids.push_back(icon_mappings[i].icon_id);
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
22692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
22702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_size_in_dip, desired_scale_factors, favicon_bitmap_results);
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
22732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success && !favicon_bitmap_results->empty();
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
22770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& candidate_favicon_ids,
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
22800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* favicon_bitmap_results) {
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_bitmap_results->clear();
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_favicon_ids.empty())
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the FaviconID and the FaviconBitmapIDs which best match
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |desired_size_in_dip| and |desired_scale_factors|.
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Select bitmap results from multiple favicons once
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // content::FaviconStatus supports multiple icon URLs.
22900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID best_favicon_id = 0;
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapID> best_bitmap_ids;
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float highest_score = kSelectFaviconFramesInvalidScore;
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &bitmap_id_sizes);
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build vector of gfx::Size from |bitmap_id_sizes|.
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<gfx::Size> sizes;
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizes.push_back(bitmap_id_sizes[j].pixel_size);
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<size_t> candidate_bitmap_indices;
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score = 0;
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFaviconFrameIndices(sizes,
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_scale_factors,
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_size_in_dip,
23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &candidate_bitmap_indices,
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &score);
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (score > highest_score) {
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      highest_score = score;
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_favicon_id = candidate_favicon_ids[i],
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_bitmap_ids.clear();
23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
23155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_t candidate_index = candidate_bitmap_indices[j];
23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        best_bitmap_ids.push_back(
23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bitmap_id_sizes[candidate_index].bitmap_id);
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct FaviconBitmapResults from |best_favicon_id| and
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |best_bitmap_ids|.
23245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
23250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       &icon_type)) {
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time last_updated;
23330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconBitmapResult bitmap_result;
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_url = icon_url;
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_type = icon_type;
23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &last_updated,
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.bitmap_data,
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.pixel_size)) {
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.expired = (Time::Now() - last_updated) >
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromDays(kFaviconRefetchDays);
23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bitmap_result.is_valid())
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
23525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
23530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
23540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
2355b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find all the pages whose favicons we should set, we want to set it for
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the pages in the redirect chain if it redirected.
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirects;
23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirects);
23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save page <-> favicon associations.
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (history::RedirectList::const_iterator i(redirects.begin());
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != redirects.end(); ++i) {
23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPage(
23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
23750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
23760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two icon types are considered 'equivalent' if one of the icon types is
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any favicons which are orphaned as a result of the removal of the
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon mappings.
23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> unmapped_icon_ids = icon_ids;
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
23970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID>::iterator icon_id_it = std::find(
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the icon mapping already exists, avoid removing it and adding it back.
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_id_it != unmapped_icon_ids.end()) {
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unmapped_icon_ids.erase(icon_id_it);
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((icon_type == favicon_base::TOUCH_ICON &&
24070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON) ||
24080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON &&
24090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_ICON) ||
24100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == m->icon_type)) {
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->DeleteIconMapping(m->mapping_id);
24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removing the icon mapping may have orphaned the associated favicon so
24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we must recheck it. This is not super fast, but this case will get
24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered rarely, since normally a page will always map to the same
24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // favicon IDs. It will mostly happen for favicons we import.
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!thumbnail_db_->HasMappingFor(m->icon_id))
24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->DeleteFavicon(m->icon_id);
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappings_changed = true;
24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
24255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed = true;
24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetCachedRecentRedirects(
24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirect_list) {
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *redirect_list = iter->second;
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The redirect chain should have the destination URL as the last item.
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirect_list->empty());
24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirect_list->back() == page_url);
24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No known redirects, construct mock redirect chain containing |page_url|.
24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirect_list->push_back(page_url);
24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirect_list;
24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirect_list);
24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2451a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<FaviconChangedDetails> changed_details(new FaviconChangedDetails);
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirect_list.size(); ++i)
24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.insert(redirect_list[i]);
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2456a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         changed_details.PassAs<HistoryDetails>());
24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Commit() {
2460b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that a commit may not actually have been scheduled if a caller
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly calls this instead of using ScheduleCommit. Likewise, we
24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may reset the flag written by a pending commit. But this is OK! It
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will merely cause extra commits (which is kind of the idea). We
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could optimize more for this case (we may get two extra commits in
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some cases) but it hasn't been important yet.
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Somebody left a transaction open";
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2482b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleCommit() {
2489868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get())
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduled_commit_ = new CommitLaterTask(this);
249290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CancelScheduledCommit() {
2499868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get()) {
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_->Cancel();
25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_ = NULL;
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTaskImpl() {
2506b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // db went away, release all the refs.
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReleaseDBTasks();
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any canceled tasks.
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.front()->Release();
25155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.pop_front();
25165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_task_requests_.empty())
25185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the first task.
25215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryDBTaskRequest* request = db_task_requests_.front();
25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.pop_front();
25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->value->RunOnDBThread(this, db_.get())) {
25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The task is done. Notify the callback.
25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult();
25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We AddRef'd the request before adding, need to release it now.
25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->Release();
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tasks wants to run some more. Schedule it at the end of current tasks.
25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.push_back(request);
25315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // And process it after an invoke later.
253290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ReleaseDBTasks() {
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::list<HistoryDBTaskRequest*>::iterator i =
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*i)->Release();
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.clear();
25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generic operations
25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURLs(urls);
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
25565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
25585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURL(const GURL& url) {
25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURL(url);
25625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
25645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
25655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
25665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ExpireHistoryBetween(
25705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& restrict_urls,
25715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time begin_time,
25725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time end_time) {
257358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!db_)
257458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
25755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
257658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
257758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      restrict_urls.empty()) {
257858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Special case deleting all history so it can be faster and to reduce the
257958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // possibility of an information leak.
258058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DeleteAllHistory();
258158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
258258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Clearing parts of history, have the expirer do the depend
258358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
258458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
258558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Force a commit, if the user is deleting something for privacy reasons,
258658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // we want to get it on disk ASAP.
258758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Commit();
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin_time <= first_recorded_time_)
25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
25922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
25932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistoryForTimes(
25952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<base::Time>& times,
25962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time, base::Time end_time) {
2597b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (times.empty() || !db_)
25982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
25992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.begin() >= begin_time)
26012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Min time is before begin time: "
26022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
26032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.rbegin() < end_time)
26042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Max time is after end time: "
26052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
26062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::QueryOptions options;
26082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.begin_time = begin_time;
26092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.end_time = end_time;
26102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
26112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryResults results;
26122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryHistoryBasic(db_.get(), db_.get(), options, &results);
26132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1st pass: find URLs that are visited at one of |times|.
26152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<GURL> urls;
26162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
26172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (times.count(results[i].visit_time()) > 0)
26182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      urls.insert(results[i].url());
26192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
26202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (urls.empty())
26212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
26222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2nd pass: collect all visit times of those URLs.
26242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Time> times_to_expire;
26252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
26262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (urls.count(results[i].url()))
26272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.push_back(results[i].visit_time());
26282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
26292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put the times in reverse chronological order and remove
26312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // duplicates (for expirer_.ExpireHistoryForTimes()).
26322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::sort(times_to_expire.begin(), times_to_expire.end(),
26332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            std::greater<base::Time>());
26342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  times_to_expire.erase(
26352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::unique(times_to_expire.begin(), times_to_expire.end()),
26362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.end());
26372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expires by times and commit.
26392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!times_to_expire.empty());
26402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expirer_.ExpireHistoryForTimes(times_to_expire);
26412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Commit();
26422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(times_to_expire.back() >= first_recorded_time_);
26442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update |first_recorded_time_| if we expired it.
26452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (times_to_expire.back() == first_recorded_time_)
26462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
26472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
26485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistory(
26502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2651b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
26522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_first_recorded_time = false;
26532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
26552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         expire_list.begin(); it != expire_list.end(); ++it) {
26562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->begin_time < first_recorded_time_)
26592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        update_first_recorded_time = true;
26602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
26612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Commit();
26622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update |first_recorded_time_| if any deletion might have affected it.
26642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (update_first_recorded_time)
26652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_->GetStartDate(&first_recorded_time_);
26662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2670b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow url_row;
26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(*i, &url_row))
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // The URL isn't in the db; nothing to do.
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector visits;
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetVisitsForURL(url_row.id(), &visits);
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visits.empty())
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
26877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
26887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scheduled_kill_db_ = true;
26897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Don't just do the close/delete here, as we are being called by |db| and
26907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that seems dangerous.
26917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // TODO(shess): Consider changing KillHistoryDatabase() to use
26927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // RazeAndClose().  Then it can be cleared immediately.
26937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
26947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        FROM_HERE,
26957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::Bind(&HistoryBackend::KillHistoryDatabase, this));
26967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
26977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
26987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::KillHistoryDatabase() {
27007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scheduled_kill_db_ = false;
2701b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rollback transaction because Raze() cannot be called from within a
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RollbackTransaction();
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = db_->Raze();
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expirer keeps tabs on the active databases. Tell it about the
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // databases which will be closed.
2717bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  expirer_.SetDatabases(NULL, NULL, NULL);
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTask(
27255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<HistoryDBTaskRequest> request) {
2726868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(request.get());
27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool task_scheduled = !db_task_requests_.empty();
27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we up the refcount of the request. ProcessDBTaskImpl will
27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release when done with the task.
27335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->AddRef();
27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.push_back(request.get());
27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!task_scheduled) {
27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No other tasks are scheduled. Process request now.
27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessDBTaskImpl();
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::BroadcastNotifications(
27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
2743a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<HistoryDetails> details) {
27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2745b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // HistoryService -> HistoryBackend::Closing().
2746b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
2747a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    delegate_->BroadcastNotifications(type, details.Pass());
27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid HistoryBackend::NotifySyncURLsModified(URLRows* rows) {
27510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (typed_url_syncable_service_.get())
27520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    typed_url_syncable_service_->OnUrlsModified(rows);
27530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
27540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2755b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2756b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           bool archived,
2757b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           URLRows* rows) {
2758b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
2759b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsDeleted(all_history, archived, rows);
2760b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
2761b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
27625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deleting --------------------------------------------------------------------
27635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllHistory() {
27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our approach to deleting all history is:
27665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  1. Copy the bookmarks and their dependencies to new tables with temporary
27675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     names.
27685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  2. Delete the original tables. Since tables can not share pages, we know
27695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     that any data we don't want to keep is now in an unused page.
27705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  3. Renaming the temporary tables to match the original.
27715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  4. Vacuuming the database to delete the unused pages.
27725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
27735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we are likely to have very few bookmarks and their dependencies
27745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compared to all history, this is also much faster than just deleting from
27755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original tables directly.
27765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bookmarked URLs.
27785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BookmarkService::URLAndTitle> starred_urls;
27795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkService* bookmark_service = GetBookmarkService();
27805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service)
27815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->GetBookmarks(&starred_urls);
27825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRows kept_urls;
27845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < starred_urls.size(); i++) {
27855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
27865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(starred_urls[i].url, &row))
27875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
27885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear the last visit time so when we write these rows they are "clean."
27905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_last_visit(Time());
27915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_visit_count(0);
27925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_typed_count(0);
27935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kept_urls.push_back(row);
27945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear thumbnail and favicon history. The favicons for the given URLs will
27975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be kept.
27983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClearAllThumbnailHistory(kept_urls)) {
27995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Thumbnail history could not be cleared";
28005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We continue in this error case. If the user wants to delete their
28015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // history, we should delete as much as we can.
28025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
280458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
280558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Therefore, we clear the list afterwards to make sure nobody uses this
280658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // invalid data.
28075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllMainHistory(kept_urls))
28085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Main history could not be cleared";
28095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kept_urls.clear();
28105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2811bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete archived history.
2812b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
28135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Close the database and delete the file.
28145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
28152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath archived_file_name = GetArchivedFileName();
2816eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(archived_file_name);
28175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now re-initialize the database (which may fail).
28195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset(new ArchivedDatabase());
28205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!archived_db_->Init(archived_file_name)) {
28215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Could not initialize the archived database.";
28225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_.reset();
28235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
28245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Open our long-running transaction on this database.
28255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_->BeginTransaction();
28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
28275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
28305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
283158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Send out the notification that history is cleared. The in-memory database
28325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will pick this up and clear itself.
2833a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails);
28345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->all_history = true;
2835b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NotifySyncURLsDeleted(true, false, NULL);
2836a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
2837a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         details.PassAs<HistoryDetails>());
28385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2841b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
28425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we have no reference to the thumbnail database, maybe there was an
28435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error opening it. In this case, we just try to blow it away to try to
28445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fix the error if it exists. This may fail, in which case either the
28455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file doesn't exist or there's no more we can do.
28463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sql::Connection::Delete(GetFaviconsFileName());
28473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
28483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Older version of the database.
2849eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(GetThumbnailFileName());
28505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
28515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Urls to retain mappings for.
28543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<GURL> urls_to_keep;
28553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin();
28563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != kept_urls.end(); ++i) {
28573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    urls_to_keep.push_back(i->url());
28583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
28595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Isolate from any long-running transaction.
28613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
28623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
28635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): If this fails, perhaps the database should be razed
28653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // or deleted.
28663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
28673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->RollbackTransaction();
28683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
28693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
28705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
28725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
28735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
28745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avaliable in HistoryBackend.
28755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->ClearAndroidURLRows();
28765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
28775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to remove all the pages associated with the dropped tables. There
28795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must be no transaction open on the table when we do this. We assume that
28805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our long-running transaction is open, so we complete it and start it again.
28815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thumbnail_db_->transaction_nesting() == 1);
28825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
28835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->Vacuum();
28845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
28855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
28865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
28895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the duplicate URL table. We will copy the kept URLs into this.
28905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CreateTemporaryURLTable())
28915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
28925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
289358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Insert the URLs into the temporary table.
28945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
28955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
289658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    db_->AddTemporaryURL(*i);
28975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the original URL table with the temporary one.
29005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CommitTemporaryURLTable())
29015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
29025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the old tables and recreate them empty.
29045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RecreateAllTablesButURL();
29055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to reclaim the space from the dropped tables. This must be done
29075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when there is no transaction open, and we assume that our long-running
29085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction is currently open.
29095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
29105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->Vacuum();
29115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
29125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
29135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
29155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkService* HistoryBackend::GetBookmarkService() {
29185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service_)
29195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->BlockTillLoaded();
29205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bookmark_service_;
29215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
29245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BriefVisitInfo info;
29255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.url_id = visit.url_id;
29265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.time = visit.visit_time;
29275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.transition = visit.transition;
29285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a delegate yet during setup or shutdown, we will drop
29295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these notifications.
2930b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
29315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->NotifyVisitDBObserversOnAddVisit(info);
29325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2934eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
2935eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::PopulateMostVisitedURLMap() {
2936eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MostVisitedURLList most_visited_urls;
2937eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
2938eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           &most_visited_urls);
2939eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2940eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2941eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2942eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    most_visited_urls_map_[most_visited_urls[i].url] = i;
2943eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2944eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2945eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2946eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2947eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2948eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2949eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rank = kPageVisitStatsMaxTopSites;
2950eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2951eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it != most_visited_urls_map_.end())
2952eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    rank = (*it).second;
2953eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2954eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            rank, kPageVisitStatsMaxTopSites + 1);
2955eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2956eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2957eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
29585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
2959