history_backend.cc revision 010d83a9304c5a91596085d917d248abff47903a
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"
400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/bookmarks/core/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) ||
410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        origin_url.SchemeIs(content::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;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // GetMostRecentRedirectsTo(url, &details->redirects);
788a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED,
789a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
800b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
8040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<URLsModifiedDetails> modified_in_archive(new URLsModifiedDetails);
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We will add to either the archived database or the main one depending on
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the date of the added visit.
8100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    URLDatabase* url_database = NULL;
8110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    VisitDatabase* visit_database = NULL;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit())) {
813b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      if (!archived_db_)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;  // No archived database to save it to, just forget this.
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = archived_db_.get();
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = archived_db_.get();
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = db_.get();
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = db_.get();
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = url_database->GetRowForURL(i->url(), &existing_url);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_id = url_database->AddURL(*i);
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i->typed_count() > 0) {
8330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // Collect expired URLs that belong to |archived_db_| separately; we
8340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // want to fire NOTIFICATION_HISTORY_URLS_MODIFIED only for changes that
8350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // take place in the main |db_|.
8360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (url_database == db_.get()) {
8370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified->changed_urls.push_back(*i);
8380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified->changed_urls.back().set_id(url_id);  // i->id_ is likely 0.
8390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        } else {
8400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified_in_archive->changed_urls.push_back(*i);
8410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          modified_in_archive->changed_urls.back().set_id(url_id);
8420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          content::PageTransitionFromInt(
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_LINK |
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_START |
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_END), 0);
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!visit_database->AddVisit(&visit_info, visit_source)) {
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (typed_url_syncable_service_.get()) {
8660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    typed_url_syncable_service_->OnUrlsModified(
8670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        &modified_in_archive->changed_urls);
868b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
8690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
870b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
877a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         modified.PassAs<HistoryDetails>());
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return time < expirer_.GetCurrentArchiveTime();
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
886a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url,
887a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  const base::string16& title) {
888b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
924b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
925b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
927a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           details.PassAs<HistoryDetails>());
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
933a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               const base::string16& title) {
934b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_info.set_title(base::UTF8ToUTF16(url.spec()));
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
95890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
960b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
975b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
981b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int max_visits,
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               VisitVector* visits) {
989b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
995b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->UpdateURLRow(id, url);
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::AddVisits(const GURL& url,
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<VisitInfo>& visits,
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               VisitSource visit_source) {
1003b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         visit != visits.end(); ++visit) {
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!AddPageVisit(
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              url, visit->first, 0, visit->second, visit_source).first) {
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1018b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.ExpireVisits(visits);
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VisitSourceMap* sources) {
1028b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetVisitsSource(visits, sources);
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1036b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetRowForURL(url, url_row) != 0;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryURL(scoped_refptr<QueryURLRequest> request,
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const GURL& url,
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool want_visits) {
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow* row = &request->value.a;
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector* visits = &request->value.b;
1050b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetRowForURL(url, row)) {
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Have a row.
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = true;
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Optionally query the visits.
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (want_visits)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetVisitsForURL(row->id(), visits);
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, row, visits);
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1063b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1064b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return typed_url_syncable_service_.get();
1065b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1066b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Segment usage ---------------------------------------------------------------
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteOldSegmentData() {
1070b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->DeleteSegmentData(Time::Now() -
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           TimeDelta::FromDays(kSegmentDataRetention));
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QuerySegmentUsage(
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time from_time,
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_result_count) {
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1082b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this is the first time we query segments, invoke
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DeleteOldSegmentData asynchronously. We do this to cleanup old
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // entries.
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!segment_queried_) {
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_ = true;
109090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->PostTask(
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keyword visits --------------------------------------------------------------
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 TemplateURLID keyword_id,
1102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                 const base::string16& term) {
1103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the ID for this URL.
11070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  URLRow row;
11080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!db_->GetRowForURL(url, &row)) {
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a small possibility the url was deleted before the keyword
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was added. Ignore the request.
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  db_->SetKeywordSearchTermsForURL(row.id(), keyword_id, term);
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(
11170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      scoped_ptr<HistoryDetails>(
11190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          new KeywordSearchUpdatedDetails(row, keyword_id, term)));
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllSearchTermsForKeyword(
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id) {
1125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->DeleteAllSearchTermsForKeyword(keyword_id);
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky): bug 1168470. Need to move from archive dbs too.
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetMostRecentKeywordSearchTerms(
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id,
1136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& prefix,
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_count) {
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &(request->value));
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void HistoryBackend::DeleteKeywordSearchTermForURL(const GURL& url) {
11490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!db_)
11500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, NULL);
11530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!url_id)
11540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
11550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  db_->DeleteKeywordSearchTermForURL(url_id);
11560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  BroadcastNotifications(
11580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
11590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_ptr<HistoryDetails>(new KeywordSearchDeletedDetails(url_id)));
11600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScheduleCommit();
11610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
11620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HistoryBackend::DeleteMatchingURLsForKeyword(TemplateURLID keyword_id,
11645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  const base::string16& term) {
11655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_)
11665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
11675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<KeywordSearchTermRow> rows;
11695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_->GetKeywordSearchTermRows(term, &rows)) {
11705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<GURL> items_to_delete;
11715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLRow row;
11725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (std::vector<KeywordSearchTermRow>::iterator it = rows.begin();
11735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it != rows.end(); ++it) {
11745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if ((it->keyword_id == keyword_id) && db_->GetURLRow(it->url_id, &row))
11755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        items_to_delete.push_back(row.url());
11765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
11775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DeleteURLs(items_to_delete);
11785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
11795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
11805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Downloads -------------------------------------------------------------------
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)uint32 HistoryBackend::GetNextDownloadId() {
1184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return db_ ? db_->GetNextDownloadId() : content::DownloadItem::kInvalidId;
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get all the download entries from the database.
11882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1189b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QueryDownloads(rows);
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update a particular download entry.
11942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->UpdateDownload(data);
11982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HistoryBackend::CreateDownload(const history::DownloadRow& history_info) {
1202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
1203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
1204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool success = db_->CreateDownload(history_info);
12052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
1206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return success;
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_before = db_->CountDownloads();
12132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks started_removing = base::TimeTicks::Now();
12142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HistoryBackend uses a long-running Transaction that is committed
12152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // periodically, so this loop doesn't actually hit the disk too hard.
12167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::set<uint32>::const_iterator it = ids.begin();
12177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       it != ids.end(); ++it) {
12182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->RemoveDownload(*it);
12192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScheduleCommit();
12212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks finished_removing = base::TimeTicks::Now();
12227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_after = db_->CountDownloads();
12237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
12247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_LE(downloads_count_after, downloads_count_before);
12257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (downloads_count_after > downloads_count_before)
12267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
12287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
12297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        num_downloads_deleted);
12307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeDelta micros = (1000 * (finished_removing - started_removing));
12317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
12327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (num_downloads_deleted > 0) {
12337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
12347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        (1000 * micros) / num_downloads_deleted);
12352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GE(ids.size(), num_downloads_deleted);
12377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (ids.size() < num_downloads_deleted)
12387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
12407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        ids.size() - num_downloads_deleted);
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
1244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  const base::string16& text_query,
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const QueryOptions& options) {
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1251b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (text_query.empty()) {
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Basic history query for the main database.
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Now query the archived database. This is a bit tricky because we don't
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // want to query it if the queried time range isn't going to find anything
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // in it.
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(brettw) bug 1171036: do blimpie querying for the archived database
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // as well.
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if (archived_db_.get() &&
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Text history query.
1265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      QueryHistoryText(db_.get(), db_.get(), text_query, options,
1266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                       &request->value);
1267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (archived_db_.get() &&
1268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          expirer_.GetCurrentArchiveTime() >= options.begin_time) {
1269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        QueryHistoryText(archived_db_.get(), archived_db_.get(), text_query,
1270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         options, &request->value);
1271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.QueryHistory",
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic time-based querying of history.
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       VisitDatabase* visit_db,
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const QueryOptions& options,
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QueryResults* result) {
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First get all visits.
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
12882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits);
12892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add them and the URL rows to the results.
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); i++) {
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VisitRow visit = visits[i];
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add a result row for this visit, get the URL info from the DB.
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_db->GetURLRow(visit.url_id, &url_result)) {
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to get id " << visit.url_id
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " from history.urls.";
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // DB out of sync and URL doesn't exist, try to recover.
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid()) {
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Got invalid URL from history.urls with id "
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << visit.url_id << ":  "
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << url_result.url().possibly_invalid_spec();
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The archived database may be out of sync with respect to starring,
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // titles, last visit date, etc. Therefore, we query the main DB if the
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // current URL database is not the main one.
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url_db == db_.get()) {
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Currently querying the archived DB, update with the main database to
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // catch any interesting stuff. This will update it if it exists in the
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // main DB, and do nothing otherwise.
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetRowForURL(url_result.url(), &url_result);
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(visit.visit_time);
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Set whether the visit was blocked for a managed user by looking at the
1323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // transition type.
1324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url_result.set_blocked_visit(
1325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't set any of the query-specific parts of the URLResult, since
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // snippets and stuff don't apply to basic querying.
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_more_results && options.begin_time <= first_recorded_time_)
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Text-based querying of history.
1337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::QueryHistoryText(URLDatabase* url_db,
1338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      VisitDatabase* visit_db,
1339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      const base::string16& text_query,
1340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const QueryOptions& options,
1341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      QueryResults* result) {
1342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  URLRows text_matches;
1343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  url_db->GetTextMatches(text_query, &text_matches);
1344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<URLResult> matching_visits;
1346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VisitVector visits;    // Declare outside loop to prevent re-construction.
1347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < text_matches.size(); i++) {
1348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const URLRow& text_match = text_matches[i];
1349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Get all visits for given URL match.
13504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    visit_db->GetVisibleVisitsForURL(text_match.id(), options, &visits);
1351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < visits.size(); j++) {
1352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      URLResult url_result(text_match);
1353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_result.set_visit_time(visits[j].visit_time);
1354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      matching_visits.push_back(url_result);
1355eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::sort(matching_visits.begin(), matching_visits.end(),
1359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            URLResult::CompareVisitTime);
1360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t max_results = options.max_count == 0 ?
1362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (std::vector<URLResult>::iterator it = matching_visits.begin();
1364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != matching_visits.end() && result->size() < max_results; ++it) {
1365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->AppendURLBySwapping(&(*it));
1366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (matching_visits.size() == result->size() &&
1369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      options.begin_time <= first_recorded_time_)
1370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->set_reached_beginning(true);
1371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Frontend to GetMostRecentRedirectsFrom from the history thread.
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsFrom(
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsFrom(url, &request->value);
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsTo(
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsTo(url, &request->value);
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetVisibleVisitCountToHost(
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetVisibleVisitCountToHostRequest> request,
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time first_visit;
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool success = db_.get() &&
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, count, first_visit);
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryTopURLsAndRedirects(
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count) {
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1410b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), false, NULL, NULL);
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL>* top_urls = &request->value.a;
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectMap* redirects = &request->value.b;
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_count, &data.get());
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_urls->push_back(data[i]->GetURL());
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*redirects)[top_urls->back()] = list;
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), true, top_urls, redirects);
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Will replace QueryTopURLsAndRedirectsRequest.
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLs(
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryMostVisitedURLsRequest> request,
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count,
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int days_back) {
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1440b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), MostVisitedURLList());
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURLList* result = &request->value;
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  QueryMostVisitedURLsImpl(result_count, days_back, result);
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), *result);
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryFilteredURLs(
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<QueryFilteredURLsRequest> request,
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int result_count,
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const history::VisitFilter& filter,
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool extended_info)  {
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time request_start = base::Time::Now();
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1461b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), FilteredURLList());
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, double> score_map;
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); ++i) {
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(georgey): experiment with visit_segment database granularity (it is
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently 24 hours) to use it directly instead of using visits database,
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is considerably slower.
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.reserve(score_map.size());
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<URLID, double>::iterator it = score_map.begin();
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != score_map.end(); ++it) {
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* pud = new PageUsageData(it->first);
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pud->SetScore(it->second);
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.push_back(pud);
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit to the top |result_count| results.
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
14892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_count && implicit_cast<int>(data.size()) > result_count)
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.resize(result_count);
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow info;
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetURLRow(data[i]->GetID(), &info)) {
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetURL(info.url());
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetTitle(info.title());
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilteredURLList& result = request->value;
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilteredURL url(*current_data);
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extended_info) {
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitVector visits;
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisitsForURL(current_data->GetID(), &visits);
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits.size() > 0) {
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url.extended_info.total_visits = visits.size();
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < visits.size(); ++i) {
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url.extended_info.duration_opened +=
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visits[i].visit_duration.InSeconds();
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (visits[i].visit_time > url.extended_info.last_visit_time) {
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url.extended_info.last_visit_time = visits[i].visit_time;
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(macourteau): implement the url.extended_info.visits stat.
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.push_back(url);
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta_time = std::max(1, std::min(999,
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATIC_HISTOGRAM_POINTER_BLOCK(
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NewTabPage.SuggestedSitesLoadTime",
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Add(delta_time),
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), result);
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              int days_back,
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              MostVisitedURLList* result) {
1537b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() -
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromDays(days_back),
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         result_count, &data.get());
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects;
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back(url);
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsFromSpecificVisit(
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit, history::RedirectList* redirects) {
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow any redirects from the given visit and add them to the list.
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It *should* be impossible to get a circular chain here, but we check
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just in case to avoid infinite loops.
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsToSpecificVisit(
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit,
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow redirects going to cur_visit. These are added to |redirects| in
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the order they are found. If a redirect chain looks like A -> B -> C and
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |cur_visit| = C, redirects will be {B, A} in that order.
1578b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsFrom(
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& from_url,
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1598b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsFromSpecificVisit(cur_visit, redirects);
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsTo(
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& to_url,
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1614b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsToSpecificVisit(cur_visit, redirects);
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          HistoryURLProviderParams* params) {
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExecuteWithDB should handle the NULL database case.
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->ExecuteWithDB(this, db_.get(), params);
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1632bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid HistoryBackend::DeleteFTSIndexDatabases() {
1633bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Find files on disk matching the text databases file pattern so we can
1634bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // quickly test for and delete them.
1635bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath::StringType filepattern =
1636bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FILE_PATH_LITERAL("History Index *");
1637bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FileEnumerator enumerator(
1638bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      history_dir_, false, base::FileEnumerator::FILES, filepattern);
1639bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  int num_databases_deleted = 0;
1640bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath current_file;
1641bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  while (!(current_file = enumerator.Next()).empty()) {
1642bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (sql::Connection::Delete(current_file))
1643bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      num_databases_deleted++;
1644bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1645bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1646bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                       num_databases_deleted);
1647bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
1648bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFavicons(
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
16532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
16540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
16552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types,
16562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
16572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void HistoryBackend::GetLargestFaviconForURL(
16610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const GURL& page_url,
16620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<int>& icon_types,
16630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int minimum_size_in_pixels,
16640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconBitmapResult* favicon_bitmap_result) {
16658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(favicon_bitmap_result);
16668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
16688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
16698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
16718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
16738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
16748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      icon_mappings.empty())
16758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
16768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int required_icon_types = 0;
16788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator i = icon_types.begin();
16798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_types.end(); ++i) {
16808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    required_icon_types |= *i;
16818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
16828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
16838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find the largest bitmap for each IconType placing in
16848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // |largest_favicon_bitmaps|.
16850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::map<favicon_base::IconType, FaviconBitmap> largest_favicon_bitmaps;
16868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
16878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       i != icon_mappings.end(); ++i) {
16888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!(i->icon_type & required_icon_types))
16898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      continue;
16908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
16918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
16928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
16938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (std::vector<FaviconBitmapIDSize>::const_iterator j =
16948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)             bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
16958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (largest.bitmap_id == 0 ||
16968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest.pixel_size.width() < j->pixel_size.width() &&
16978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           largest.pixel_size.height() < j->pixel_size.height())) {
16988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.icon_id = i->icon_id;
16998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.bitmap_id = j->bitmap_id;
17008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest.pixel_size = j->pixel_size;
17018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
17028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
17038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (largest_favicon_bitmaps.empty())
17058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
17068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find an icon which is larger than minimum_size_in_pixels in the order of
17088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // icon_types.
17098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FaviconBitmap largest_icon;
17108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<int>::const_iterator t = icon_types.begin();
17118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       t != icon_types.end(); ++t) {
17120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (std::map<favicon_base::IconType, FaviconBitmap>::const_iterator f =
17130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             largest_favicon_bitmaps.begin();
17140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         f != largest_favicon_bitmaps.end();
17150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++f) {
17168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (f->first & *t &&
17178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (largest_icon.bitmap_id == 0 ||
17188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
17198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
17208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon = f->second;
17218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
17228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
17238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
17248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        largest_icon.pixel_size.height() > minimum_size_in_pixels)
17258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
17268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  GURL icon_url;
17290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
17308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
17318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &icon_type)) {
17328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
17338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::Time last_updated;
17360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconBitmapResult bitmap_result;
17378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_url = icon_url;
17388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.icon_type = icon_type;
17398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
17408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &last_updated,
17418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.bitmap_data,
17428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       &bitmap_result.pixel_size)) {
17438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
17448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
17458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bitmap_result.expired = (Time::Now() - last_updated) >
17478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      TimeDelta::FromDays(kFaviconRefetchDays);
17488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (bitmap_result.is_valid())
17498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    *favicon_bitmap_result = bitmap_result;
17508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
17528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                  TimeTicks::Now() - beginning_time);
17538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
17548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFaviconsForURL(
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
17592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
17600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
17612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_results);
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconsFromDB(page_url, icon_types, desired_size_in_dip,
17632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    desired_scale_factors, bitmap_results);
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetFaviconForID(
17670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id,
17682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int desired_size_in_dip,
17692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ScaleFactor desired_scale_factor,
17700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
17710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_ids.push_back(favicon_id);
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::ScaleFactor> desired_scale_factors;
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desired_scale_factors.push_back(desired_scale_factor);
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get results from DB.
17772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids,
17782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_size_in_dip,
17792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_scale_factors,
17802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bitmap_results);
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetch(
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
17882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
17890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
17902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
17912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
17922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MergeFavicon(
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url,
17980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
1801b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID favicon_id =
180590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!favicon_id) {
18082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is no favicon at |icon_url|, create it.
1809eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
18102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
18132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
18162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // replace it.
18172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bitmap_identical = false;
18182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool replaced_bitmap = false;
18192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
18202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
18212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
18222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
18232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
18242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bitmap_identical = true;
18252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
18262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
18272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_data, base::Time::Now());
18282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        replaced_bitmap = true;
18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
18302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a vector of the pixel sizes of the favicon bitmaps currently at
18352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url|.
18362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
18372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
18382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!replaced_bitmap && !bitmap_identical) {
18412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
18422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmaps are not consistent with the merged in data.
18432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delete an arbitrary favicon bitmap to avoid going over the limit of
18462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |kMaxFaviconBitmapsPerIconURL|.
18472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
18482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
18492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.erase(favicon_sizes.begin());
18502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
18522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    pixel_size);
18532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(pixel_size);
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A site may have changed the favicons that it uses for |page_url|.
18572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Example Scenario:
18582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   page_url = news.google.com
185958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //   Initial State: www.google.com/favicon.ico 16x16, 32x32
18602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
18612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //                ..., 16x16)
18622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulties:
18642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1. Sync requires that a call to GetFaviconsForURL() returns the
18652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    |bitmap_data| passed into MergeFavicon().
18662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
18672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      stay mapped to news.google.com because it would be unclear which 16x16
18682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      bitmap should be returned via GetFaviconsForURL().
18692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2. www.google.com/favicon.ico may be mapped to more than just
18712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    news.google.com (eg www.google.com).
18722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
18732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
18742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To resolve these problems, we copy all of the favicon bitmaps previously
18752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mapped to news.google.com (|page_url|) and add them to the favicon at
18762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
18772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url| are set to default to indicate that |icon_url| has incomplete
18782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // / incorrect data.
187958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
18802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //              news.google.com
18812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
18822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //               modified.
18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
18852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
18882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
18892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i) {
18902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
18912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (icon_mappings[i].icon_url == icon_url)
18942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmap> bitmaps_to_copy;
18972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
18982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     &bitmaps_to_copy);
18992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
19002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Do not add a favicon bitmap at a pixel size for which there is already
19012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // a favicon bitmap mapped to |icon_url|. The one there is more correct
19022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // and having multiple equally sized favicon bitmaps for |page_url| is
19032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ambiguous in terms of GetFaviconsForURL().
19042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
19052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
19062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != favicon_sizes.end())
19072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
19082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add the favicon bitmap as expired as it is not consistent with the
19102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // merged in data.
19112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->AddFaviconBitmap(favicon_id,
19122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].bitmap_data, base::Time(),
19132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].pixel_size);
19142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
19152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
19172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
19182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
19192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the favicon mappings such that only |icon_url| is mapped to
19222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |page_url|.
19232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool mapping_changed = false;
19242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
19250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID> favicon_ids;
19262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_ids.push_back(favicon_id);
19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
19282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mapping_changed = true;
19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (mapping_changed || !bitmap_identical)
19322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFavicons(
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
19380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
19390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapData>& favicon_bitmap_data) {
1940b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build map of FaviconBitmapData for each icon url.
19460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef std::map<GURL, std::vector<favicon_base::FaviconBitmapData> >
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BitmapDataByIconURL;
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitmapDataByIconURL grouped_by_icon_url;
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track whether the method modifies or creates any favicon bitmaps, favicons
19552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // or icon mappings.
19562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool data_modified = false;
19572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> icon_ids;
19592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
19602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != grouped_by_icon_url.end(); ++it) {
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = it->first;
19620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id =
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
19642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!icon_id) {
19662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Remove the favicon sizes attribute from
19672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ThumbnailDatabase::AddFavicon().
1968eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
19692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_modified = true;
19702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_ids.push_back(icon_id);
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!data_modified)
19742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, &data_modified);
19752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
19762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, NULL);
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_modified |=
19802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_modified) {
19832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Send notification to the UI as an icon mapping, favicon, or favicon
19842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmap was changed by this function.
19852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
19862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1993b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ ||
19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &icon_mappings))
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloneFavicons(const GURL& old_page_url,
20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& new_page_url) {
2007b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent cross-domain cloning.
20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetImportedFavicons(
20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ImportedFaviconUsage>& favicon_usage) {
2020b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Track all URLs that had their favicons set or updated.
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> favicons_changed;
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_usage.size(); i++) {
20290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID favicon_id =
20300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        thumbnail_db_->GetFaviconIDForFaviconURL(
20310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            favicon_usage[i].favicon_url, favicon_base::FAVICON, NULL);
20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_id) {
20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This favicon doesn't exist yet, so we create it using the given data.
20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkotwicz): Pass in real pixel size.
20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_id = thumbnail_db_->AddFavicon(
20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_usage[i].favicon_url,
20370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          favicon_base::FAVICON,
20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new base::RefCountedBytes(favicon_usage[i].png_data),
20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          now,
20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::Size());
20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the mapping from all the URLs to the favicon.
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkService* bookmark_service = GetBookmarkService();
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url != favicon_usage[i].urls.end(); ++url) {
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow url_row;
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!db_->GetRowForURL(*url, &url_row)) {
20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the URL is present as a bookmark, add the url in history to
20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // save the favicon mapping. This will match with what history db does
20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for regular bookmarked URLs with favicons - when history db is
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // cleaned, we keep an entry in the db with 0 visits as long as that
20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // url is bookmarked.
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (bookmark_service && bookmark_service_->IsBookmarked(*url)) {
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          URLRow url_info(*url);
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_visit_count(0);
20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_typed_count(0);
20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_last_visit(base::Time());
20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_hidden(false);
20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->AddURL(url_info);
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
206590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!thumbnail_db_->GetIconMappingsForPageURL(
20660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                *url, favicon_base::FAVICON, NULL)) {
20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // URL is present in history, update the favicon *only* if it is not
20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // set already.
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!favicons_changed.empty()) {
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the notification about the changed favicon URLs.
2078a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<FaviconChangedDetails> changed_details(
2079a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new FaviconChangedDetails);
20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.swap(favicons_changed);
20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2082a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           changed_details.PassAs<HistoryDetails>());
20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* page_url,
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
20912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
20920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* bitmap_results) {
20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |page_url| is specified, |icon_types| must be either a single icon
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type or icon types which are equivalent.
20950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!page_url || icon_types == favicon_base::FAVICON ||
20960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_ICON ||
20970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types == favicon_base::TOUCH_PRECOMPOSED_ICON ||
20980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         icon_types ==
20990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             (favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON));
21002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bitmap_results->clear();
21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The icon type for which the mappings will the updated and data will be
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned.
21100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType selected_icon_type = favicon_base::INVALID_ICON;
21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_urls.size(); ++i) {
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = icon_urls[i];
21140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type_out;
21150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const favicon_base::FaviconID favicon_id =
211690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(
211790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            icon_url, icon_types, &icon_type_out);
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_id) {
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Return and update icon mappings only for the largest icon type. As
21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if an |icon_url| with a larger icon type is found.
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out > selected_icon_type) {
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_icon_type = icon_type_out;
21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.clear();
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out == selected_icon_type)
21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.push_back(favicon_id);
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_url && !favicon_ids.empty()) {
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool mappings_updated =
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              favicon_ids);
21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappings_updated) {
21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommit();
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_size_in_dip,
21432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_scale_factors, bitmap_results);
21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconBitmaps(
21470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id,
21480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapData>& favicon_bitmap_data,
21492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* favicon_bitmaps_changed) {
21502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_bitmaps_changed)
21512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *favicon_bitmaps_changed = false;
21522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconBitmapData> to_add = favicon_bitmap_data;
21572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
21592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
21600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapData>::iterator match_it =
21610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        to_add.end();
21620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (std::vector<favicon_base::FaviconBitmapData>::iterator it =
21630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             to_add.begin();
21640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         it != to_add.end();
21650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++it) {
21662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->pixel_size == pixel_size) {
21672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        match_it = it;
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
21732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (match_it == to_add.end()) {
21742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
21752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed)
21772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *favicon_bitmaps_changed = true;
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
21792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed &&
21802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !*favicon_bitmaps_changed &&
21812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
21822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
21832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id, base::Time::Now());
21842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
21852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
21862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Time::Now());
21872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (favicon_bitmaps_changed)
21892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *favicon_bitmaps_changed = true;
21902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
21912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      to_add.erase(match_it);
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < to_add.size(); ++i) {
21962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
21972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time::Now(), to_add[i].pixel_size);
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_bitmaps_changed)
22002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *favicon_bitmaps_changed = true;
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool HistoryBackend::ValidateSetFaviconsParams(const std::vector<
22050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconBitmapData>& favicon_bitmap_data) const {
22062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<GURL, size_t> BitmapsPerIconURL;
22072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BitmapsPerIconURL num_bitmaps_per_icon_url;
22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!favicon_bitmap_data[i].bitmap_data.get())
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
22132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!num_bitmaps_per_icon_url.count(icon_url))
22142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_bitmaps_per_icon_url[icon_url] = 1u;
22152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
22162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++num_bitmaps_per_icon_url[icon_url];
22172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
22182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
22192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
22202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
22232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != num_bitmaps_per_icon_url.end(); ++it) {
22242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->second > kMaxFaviconBitmapsPerIconURL)
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::IsFaviconBitmapDataEqual(
22312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
22322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!new_bitmap_data.get())
22342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
22372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmap(bitmap_id,
22382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL,
22392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  &original_bitmap_data,
22402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL);
22412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_bitmap_data->Equals(original_bitmap_data);
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconsFromDB(
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
22490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* favicon_bitmap_results) {
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(favicon_bitmap_results);
22512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_bitmap_results->clear();
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2253b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Time the query.
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get FaviconIDs for |page_url| and one of |icon_types|.
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &icon_mappings);
22630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> favicon_ids;
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i)
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ids.push_back(icon_mappings[i].icon_id);
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
22682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
22692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_size_in_dip, desired_scale_factors, favicon_bitmap_results);
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
22722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success && !favicon_bitmap_results->empty();
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
22760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& candidate_favicon_ids,
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
22790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconBitmapResult>* favicon_bitmap_results) {
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_bitmap_results->clear();
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_favicon_ids.empty())
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the FaviconID and the FaviconBitmapIDs which best match
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |desired_size_in_dip| and |desired_scale_factors|.
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Select bitmap results from multiple favicons once
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // content::FaviconStatus supports multiple icon URLs.
22890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID best_favicon_id = 0;
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapID> best_bitmap_ids;
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float highest_score = kSelectFaviconFramesInvalidScore;
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &bitmap_id_sizes);
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build vector of gfx::Size from |bitmap_id_sizes|.
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<gfx::Size> sizes;
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizes.push_back(bitmap_id_sizes[j].pixel_size);
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<size_t> candidate_bitmap_indices;
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score = 0;
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFaviconFrameIndices(sizes,
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_scale_factors,
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_size_in_dip,
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &candidate_bitmap_indices,
23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &score);
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (score > highest_score) {
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      highest_score = score;
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_favicon_id = candidate_favicon_ids[i],
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_bitmap_ids.clear();
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_t candidate_index = candidate_bitmap_indices[j];
23155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        best_bitmap_ids.push_back(
23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bitmap_id_sizes[candidate_index].bitmap_id);
23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct FaviconBitmapResults from |best_favicon_id| and
23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |best_bitmap_ids|.
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
23240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::IconType icon_type;
23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       &icon_type)) {
23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time last_updated;
23320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconBitmapResult bitmap_result;
23335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_url = icon_url;
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_type = icon_type;
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &last_updated,
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.bitmap_data,
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.pixel_size)) {
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.expired = (Time::Now() - last_updated) >
23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromDays(kFaviconRefetchDays);
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bitmap_result.is_valid())
23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
23520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
23530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
2354b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
23555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find all the pages whose favicons we should set, we want to set it for
23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the pages in the redirect chain if it redirected.
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirects;
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirects);
23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save page <-> favicon associations.
23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (history::RedirectList::const_iterator i(redirects.begin());
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != redirects.end(); ++i) {
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPage(
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
23740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
23750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconID>& icon_ids) {
23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two icon types are considered 'equivalent' if one of the icon types is
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any favicons which are orphaned as a result of the removal of the
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon mappings.
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconID> unmapped_icon_ids = icon_ids;
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
23960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<favicon_base::FaviconID>::iterator icon_id_it = std::find(
23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the icon mapping already exists, avoid removing it and adding it back.
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_id_it != unmapped_icon_ids.end()) {
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unmapped_icon_ids.erase(icon_id_it);
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((icon_type == favicon_base::TOUCH_ICON &&
24060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON) ||
24070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == favicon_base::TOUCH_PRECOMPOSED_ICON &&
24080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         m->icon_type == favicon_base::TOUCH_ICON) ||
24090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        (icon_type == m->icon_type)) {
24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->DeleteIconMapping(m->mapping_id);
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removing the icon mapping may have orphaned the associated favicon so
24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we must recheck it. This is not super fast, but this case will get
24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered rarely, since normally a page will always map to the same
24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // favicon IDs. It will mostly happen for favicons we import.
24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!thumbnail_db_->HasMappingFor(m->icon_id))
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->DeleteFavicon(m->icon_id);
24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappings_changed = true;
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed = true;
24255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetCachedRecentRedirects(
24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirect_list) {
24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *redirect_list = iter->second;
24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The redirect chain should have the destination URL as the last item.
24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirect_list->empty());
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirect_list->back() == page_url);
24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No known redirects, construct mock redirect chain containing |page_url|.
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirect_list->push_back(page_url);
24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirect_list;
24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirect_list);
24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<FaviconChangedDetails> changed_details(new FaviconChangedDetails);
24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirect_list.size(); ++i)
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.insert(redirect_list[i]);
24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         changed_details.PassAs<HistoryDetails>());
24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Commit() {
2459b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that a commit may not actually have been scheduled if a caller
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly calls this instead of using ScheduleCommit. Likewise, we
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may reset the flag written by a pending commit. But this is OK! It
24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will merely cause extra commits (which is kind of the idea). We
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could optimize more for this case (we may get two extra commits in
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some cases) but it hasn't been important yet.
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2474b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Somebody left a transaction open";
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2481b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleCommit() {
2488868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get())
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduled_commit_ = new CommitLaterTask(this);
249190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CancelScheduledCommit() {
2498868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get()) {
24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_->Cancel();
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_ = NULL;
25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTaskImpl() {
2505b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // db went away, release all the refs.
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReleaseDBTasks();
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any canceled tasks.
25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.front()->Release();
25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.pop_front();
25155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_task_requests_.empty())
25175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the first task.
25205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryDBTaskRequest* request = db_task_requests_.front();
25215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.pop_front();
25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->value->RunOnDBThread(this, db_.get())) {
25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The task is done. Notify the callback.
25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult();
25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We AddRef'd the request before adding, need to release it now.
25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->Release();
25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tasks wants to run some more. Schedule it at the end of current tasks.
25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.push_back(request);
25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // And process it after an invoke later.
253190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
25325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ReleaseDBTasks() {
25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::list<HistoryDBTaskRequest*>::iterator i =
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*i)->Release();
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.clear();
25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generic operations
25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURLs(urls);
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
25565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURL(const GURL& url) {
25605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURL(url);
25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
25645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
25655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
25665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ExpireHistoryBetween(
25695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& restrict_urls,
25705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time begin_time,
25715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time end_time) {
257258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!db_)
257358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
25745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
257558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
257658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      restrict_urls.empty()) {
257758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Special case deleting all history so it can be faster and to reduce the
257858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // possibility of an information leak.
257958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DeleteAllHistory();
258058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
258158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Clearing parts of history, have the expirer do the depend
258258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
258358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
258458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Force a commit, if the user is deleting something for privacy reasons,
258558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // we want to get it on disk ASAP.
258658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Commit();
25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin_time <= first_recorded_time_)
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
25912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
25922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistoryForTimes(
25942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<base::Time>& times,
25952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time, base::Time end_time) {
2596b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (times.empty() || !db_)
25972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
25982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.begin() >= begin_time)
26002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Min time is before begin time: "
26012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
26022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.rbegin() < end_time)
26032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Max time is after end time: "
26042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
26052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::QueryOptions options;
26072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.begin_time = begin_time;
26082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.end_time = end_time;
26092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
26102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryResults results;
26112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryHistoryBasic(db_.get(), db_.get(), options, &results);
26122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1st pass: find URLs that are visited at one of |times|.
26142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<GURL> urls;
26152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
26162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (times.count(results[i].visit_time()) > 0)
26172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      urls.insert(results[i].url());
26182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
26192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (urls.empty())
26202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
26212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2nd pass: collect all visit times of those URLs.
26232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Time> times_to_expire;
26242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
26252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (urls.count(results[i].url()))
26262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.push_back(results[i].visit_time());
26272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
26282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put the times in reverse chronological order and remove
26302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // duplicates (for expirer_.ExpireHistoryForTimes()).
26312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::sort(times_to_expire.begin(), times_to_expire.end(),
26322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            std::greater<base::Time>());
26332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  times_to_expire.erase(
26342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::unique(times_to_expire.begin(), times_to_expire.end()),
26352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.end());
26362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expires by times and commit.
26382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!times_to_expire.empty());
26392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expirer_.ExpireHistoryForTimes(times_to_expire);
26402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Commit();
26412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(times_to_expire.back() >= first_recorded_time_);
26432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update |first_recorded_time_| if we expired it.
26442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (times_to_expire.back() == first_recorded_time_)
26452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
26462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistory(
26492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2650b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
26512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_first_recorded_time = false;
26522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
26542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         expire_list.begin(); it != expire_list.end(); ++it) {
26552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
26565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->begin_time < first_recorded_time_)
26582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        update_first_recorded_time = true;
26592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
26602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Commit();
26612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update |first_recorded_time_| if any deletion might have affected it.
26632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (update_first_recorded_time)
26642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_->GetStartDate(&first_recorded_time_);
26652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2669b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow url_row;
26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(*i, &url_row))
26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // The URL isn't in the db; nothing to do.
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector visits;
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetVisitsForURL(url_row.id(), &visits);
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visits.empty())
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
26867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
26877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scheduled_kill_db_ = true;
26887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Don't just do the close/delete here, as we are being called by |db| and
26897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that seems dangerous.
26907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // TODO(shess): Consider changing KillHistoryDatabase() to use
26917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // RazeAndClose().  Then it can be cleared immediately.
26927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
26937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        FROM_HERE,
26947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::Bind(&HistoryBackend::KillHistoryDatabase, this));
26957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
26967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
26977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::KillHistoryDatabase() {
26997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scheduled_kill_db_ = false;
2700b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rollback transaction because Raze() cannot be called from within a
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RollbackTransaction();
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = db_->Raze();
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expirer keeps tabs on the active databases. Tell it about the
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // databases which will be closed.
2716bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  expirer_.SetDatabases(NULL, NULL, NULL);
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTask(
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<HistoryDBTaskRequest> request) {
2725868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(request.get());
27265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool task_scheduled = !db_task_requests_.empty();
27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we up the refcount of the request. ProcessDBTaskImpl will
27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release when done with the task.
27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->AddRef();
27335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.push_back(request.get());
27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!task_scheduled) {
27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No other tasks are scheduled. Process request now.
27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessDBTaskImpl();
27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::BroadcastNotifications(
27415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
2742a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<HistoryDetails> details) {
27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2744b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // HistoryService -> HistoryBackend::Closing().
2745b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
2746a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    delegate_->BroadcastNotifications(type, details.Pass());
27475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid HistoryBackend::NotifySyncURLsModified(URLRows* rows) {
27500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (typed_url_syncable_service_.get())
27510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    typed_url_syncable_service_->OnUrlsModified(rows);
27520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
27530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2754b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2755b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           bool archived,
2756b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           URLRows* rows) {
2757b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
2758b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsDeleted(all_history, archived, rows);
2759b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
2760b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
27615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deleting --------------------------------------------------------------------
27625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllHistory() {
27645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our approach to deleting all history is:
27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  1. Copy the bookmarks and their dependencies to new tables with temporary
27665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     names.
27675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  2. Delete the original tables. Since tables can not share pages, we know
27685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     that any data we don't want to keep is now in an unused page.
27695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  3. Renaming the temporary tables to match the original.
27705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  4. Vacuuming the database to delete the unused pages.
27715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
27725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we are likely to have very few bookmarks and their dependencies
27735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compared to all history, this is also much faster than just deleting from
27745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original tables directly.
27755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bookmarked URLs.
27775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BookmarkService::URLAndTitle> starred_urls;
27785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkService* bookmark_service = GetBookmarkService();
27795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service)
27805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->GetBookmarks(&starred_urls);
27815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRows kept_urls;
27835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < starred_urls.size(); i++) {
27845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
27855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(starred_urls[i].url, &row))
27865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
27875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear the last visit time so when we write these rows they are "clean."
27895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_last_visit(Time());
27905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_visit_count(0);
27915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_typed_count(0);
27925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kept_urls.push_back(row);
27935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear thumbnail and favicon history. The favicons for the given URLs will
27965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be kept.
27973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClearAllThumbnailHistory(kept_urls)) {
27985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Thumbnail history could not be cleared";
27995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We continue in this error case. If the user wants to delete their
28005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // history, we should delete as much as we can.
28015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
280358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
280458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Therefore, we clear the list afterwards to make sure nobody uses this
280558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // invalid data.
28065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllMainHistory(kept_urls))
28075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Main history could not be cleared";
28085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kept_urls.clear();
28095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2810bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete archived history.
2811b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
28125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Close the database and delete the file.
28135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
28142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath archived_file_name = GetArchivedFileName();
2815eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(archived_file_name);
28165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now re-initialize the database (which may fail).
28185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset(new ArchivedDatabase());
28195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!archived_db_->Init(archived_file_name)) {
28205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Could not initialize the archived database.";
28215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_.reset();
28225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
28235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Open our long-running transaction on this database.
28245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_->BeginTransaction();
28255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
28295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
283058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Send out the notification that history is cleared. The in-memory database
28315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will pick this up and clear itself.
2832a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails);
28335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->all_history = true;
2834b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NotifySyncURLsDeleted(true, false, NULL);
2835a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
2836a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         details.PassAs<HistoryDetails>());
28375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2840b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
28415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we have no reference to the thumbnail database, maybe there was an
28425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error opening it. In this case, we just try to blow it away to try to
28435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fix the error if it exists. This may fail, in which case either the
28445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file doesn't exist or there's no more we can do.
28453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sql::Connection::Delete(GetFaviconsFileName());
28463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
28473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Older version of the database.
2848eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(GetThumbnailFileName());
28495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
28505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Urls to retain mappings for.
28533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<GURL> urls_to_keep;
28543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin();
28553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != kept_urls.end(); ++i) {
28563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    urls_to_keep.push_back(i->url());
28573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
28585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Isolate from any long-running transaction.
28603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
28613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
28625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): If this fails, perhaps the database should be razed
28643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // or deleted.
28653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
28663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->RollbackTransaction();
28673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
28683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
28695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
28715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
28725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
28735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avaliable in HistoryBackend.
28745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->ClearAndroidURLRows();
28755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
28765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to remove all the pages associated with the dropped tables. There
28785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must be no transaction open on the table when we do this. We assume that
28795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our long-running transaction is open, so we complete it and start it again.
28805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thumbnail_db_->transaction_nesting() == 1);
28815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
28825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->Vacuum();
28835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
28845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
28855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
28885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the duplicate URL table. We will copy the kept URLs into this.
28895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CreateTemporaryURLTable())
28905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
28915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
289258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Insert the URLs into the temporary table.
28935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
28945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
289558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    db_->AddTemporaryURL(*i);
28965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the original URL table with the temporary one.
28995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CommitTemporaryURLTable())
29005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
29015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the old tables and recreate them empty.
29035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RecreateAllTablesButURL();
29045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to reclaim the space from the dropped tables. This must be done
29065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when there is no transaction open, and we assume that our long-running
29075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction is currently open.
29085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
29095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->Vacuum();
29105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
29115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
29125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
29145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkService* HistoryBackend::GetBookmarkService() {
29175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service_)
29185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->BlockTillLoaded();
29195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bookmark_service_;
29205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
29235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BriefVisitInfo info;
29245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.url_id = visit.url_id;
29255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.time = visit.visit_time;
29265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.transition = visit.transition;
29275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a delegate yet during setup or shutdown, we will drop
29285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these notifications.
2929b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
29305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->NotifyVisitDBObserversOnAddVisit(info);
29315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2933eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
2934eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::PopulateMostVisitedURLMap() {
2935eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MostVisitedURLList most_visited_urls;
2936eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
2937eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           &most_visited_urls);
2938eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2939eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2940eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2941eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    most_visited_urls_map_[most_visited_urls[i].url] = i;
2942eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2943eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2944eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2945eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2946eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2947eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2948eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rank = kPageVisitStatsMaxTopSites;
2949eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2950eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it != most_visited_urls_map_.end())
2951eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    rank = (*it).second;
2952eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2953eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            rank, kPageVisitStatsMaxTopSites + 1);
2954eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2955eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2956eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
29575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
2958