history_backend.cc revision 58537e28ecd584eab876aee8be7156509866d23a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_backend.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <functional>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <list>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
17bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/files/file_enumerator.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/history_url_provider.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_service.h"
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/favicon/favicon_changed_details.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_publisher.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/page_usage_data.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/select_favicon_frames.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/history/typed_url_syncable_service.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/common/importer/imported_favicon_usage.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/error_delegate_util.h"
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/android/android_provider_backend.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* The HistoryBackend consists of a number of components:
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase (stores past 3 months of history)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitSegmentDatabase (stores groups of URLs for the most visited view).
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ArchivedDatabase (stores history older than 3 months)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLDatabase (stores a list of URLs)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadDatabase (stores a list of downloads)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitDatabase (stores a list of visits for the URLs)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (this does not store visit segments as they expire after 3 mos.)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExpireHistoryBackend (manages moving things from HistoryDatabase to
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          the ArchivedDatabase and deleting)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we keep segment data for in days. Currently 3 months.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This value needs to be greater or equal to
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dependency between MostVisitedModel and the history backend.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSegmentDataRetention = 90;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long we'll wait to do a commit, so that things are batched together.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kCommitIntervalSeconds = 10;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time before we re-fetch the favicon.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kFaviconRefetchDays = 7;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetSessionTabs returns all open tabs, or tabs closed kSessionCloseTimeWindow
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// seconds ago.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSessionCloseTimeWindowSecs = 10;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of items we'll allow in the redirect list before
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleting some.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxRedirectCount = 32;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of days old a history entry can be before it is considered "old"
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and is archived.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kArchiveDaysThreshold = 90;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The maximum number of top sites to track when recording top page visit stats.
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic const size_t kPageVisitStatsMaxTopSites = 50;
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts from PageUsageData to MostVisitedURL. |redirects| is a
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// list of redirects for this URL. Empty list means no redirects.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const RedirectList& redirects) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURL mv;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.url = page_data.GetURL();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mv.title = page_data.GetTitle();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (redirects.empty()) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirects must contain at least the target url.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects.push_back(mv.url);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mv.redirects = redirects;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last url must be the target url.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mv.redirects.push_back(mv.url);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mv;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This task is run on a timer so that commits happen at regular intervals
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they are batched together. The important thing about this class is that
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it supports canceling of the task so the reference to the backend will be
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// freed. The problem is that when history is shutting down, there is likely
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be one of these commits still pending and holding a reference.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The backend can call Cancel to have this task release the reference. The
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// task will still run (if we ever get to processing the event before
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown), but it will not do anything.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this is a refcounted object and is not a task in itself. It should
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be assigned to a RunnableMethod.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): bug 1165182: This should be replaced with a
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::WeakPtrFactory which will handle everything automatically (like we do
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in ExpireHistoryBackend).
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommitLaterTask(HistoryBackend* history_backend)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : history_backend_(history_backend) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The backend will call this function if it is being destroyed so that we
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release our reference.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_backend_ = NULL;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCommit() {
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (history_backend_.get())
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_backend_->Commit();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<CommitLaterTask>;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommitLaterTask() {}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HistoryBackend> history_backend_;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HistoryBackend --------------------------------------------------------------
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int id,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Delegate* delegate,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkService* bookmark_service)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_(id),
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_dir_(history_dir),
1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      scheduled_kill_db_(false),
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      expirer_(this, bookmark_service),
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recent_redirects_(kMaxRedirectCount),
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_destroy_message_loop_(NULL),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_(false),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_service_(bookmark_service) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryBackend::~HistoryBackend() {
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReleaseDBTasks();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First close the databases before optionally running the "destroy" task.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null()) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify an interested party (typically a unit test) that we're done.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_destroy_message_loop_);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sql::Connection::Delete(GetAndroidCacheFileName());
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Init(const std::string& languages, bool force_fail) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force_fail)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitImpl(languages);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->DBLoaded(id_);
212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
213ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  memory_pressure_listener_.reset(new base::MemoryPressureListener(
214ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PopulateMostVisitedURLMap();
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const base::Closure& task) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!backend_destroy_task_.is_null())
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Setting more than one destroy task, overriding";
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_message_loop_ = message_loop;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_destroy_task_ = task;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Closing() {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any scheduled commit will have a reference to us, we must make it
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release that reference before we can be destroyed.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release our reference to the delegate, this reference will be keeping the
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // history service alive.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset();
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyRenderProcessHostDestruction(const void* host) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tracker_.NotifyRenderProcessHostDestruction(host);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetThumbnailFileName() const {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kThumbnailsFilename);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetFaviconsFileName() const {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kFaviconsFilename);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetArchivedFileName() const {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kArchivedHistoryFilename);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return history_dir_.Append(chrome::kAndroidCacheFilename);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is used to detect referrer loops.  Should not happen, but can
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the database is corrupt.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = from_visit;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (visit_id) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitRow row;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForVisit(visit_id, &row))
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row.segment_id)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return row.segment_id;  // Found a visit in this change with a segment.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the referrer of this visit, if any.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_id = row.referring_visit;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(visit_id) != visit_set.end()) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in referer chain, giving up";
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(visit_id);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SegmentID HistoryBackend::UpdateSegments(
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID from_visit,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID visit_id,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition_type,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time ts) {
290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only consider main frames.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!content::PageTransitionIsMainFrame(transition_type))
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SegmentID segment_id = 0;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition t =
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition_type);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are we at the beginning of a new segment?
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that navigating to an existing entry (with back/forward) reuses the
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same transition type.  We are not adding it as a new segment in that case
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because if this was the target of a redirect, we might end up with
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2 entries for the same final URL. Ex: User types google.net, gets
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirected to google.com. A segment is created for google.net. On
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // google.com users navigates through a link, then press back. That last
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation is for the entry google.com transition typed. We end up adding
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a segment for that one as well. So we end up with google.net and google.com
31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // in the segment table, showing as 2 entries in the NTP.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note also that we should still be updating the visit count for that segment
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which we are not doing now. It should be addressed when
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://crbug.com/96860 is fixed.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((t == content::PAGE_TRANSITION_TYPED ||
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If so, create or get the segment.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string segment_name = db_->ComputeSegmentName(url);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: if we update an existing segment, we update the url used to
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // represent that segment in order to minimize stale most visited
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // images.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: it is possible there is no segment ID set for this visit chain.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TYPED. (For example GENERATED). In this case this visit doesn't count
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // toward any segment.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(segment_id = GetLastSegmentID(from_visit)))
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the segment in the visit.
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->SetSegmentID(visit_id, segment_id)) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, increase the counter for that segment / day.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return segment_id;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateWithPageEndTime(const void* host,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int32 page_id,
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const GURL& url,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Time end_ts) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = tracker_.GetLastVisit(host, page_id, url);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisitDuration(visit_id, end_ts);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
367b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the starting visit_time for visit_id.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_row;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->GetRowForVisit(visit_id, &visit_row)) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should never have a negative duration time even when time is skewed.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_row.visit_duration = end_ts > visit_row.visit_time ?
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateVisitRow(visit_row);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
381b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be filled with the URL ID and the visit ID of the last addition.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request.id_scope, request.page_id, request.referrer));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID from_visit_id = last_ids.second;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a redirect chain is given, we expect the last item in that chain to be
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the final URL.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request.redirects.empty() ||
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         request.redirects.back() == request.url);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is adding older history, we need to make sure our times
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are correct.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request.time < first_recorded_time_)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = request.time;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition request_transition = request.transition;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition stripped_transition =
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransitionStripQualifier(request_transition);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_generated =
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user is navigating to a not-previously-typed intranet hostname,
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the transition to TYPED so that the omnibox will learn that this is
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a known host.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_redirects = request.redirects.size() > 1;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (content::PageTransitionIsMainFrame(request_transition) &&
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url(has_redirects ?
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request.redirects[0] : request.url);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (origin_url.SchemeIs(chrome::kHttpScheme) ||
416424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        origin_url.SchemeIs(content::kHttpsScheme) ||
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        origin_url.SchemeIs(chrome::kFtpScheme)) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string host(origin_url.host());
419a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      size_t registry_length =
420a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          net::registry_controlled_domains::GetRegistryLength(
421a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              host,
422a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
423a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
424a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (registry_length == 0 && !db_->IsTypedHost(host)) {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stripped_transition = content::PAGE_TRANSITION_TYPED;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition =
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::PageTransitionFromInt(
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                stripped_transition |
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                content::PageTransitionGetQualifier(request_transition));
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_redirects) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The single entry is both a chain start and end.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition t = content::PageTransitionFromInt(
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_transition |
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START |
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_END);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect case (one element means just the page itself).
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_ids = AddPageVisit(request.url, request.time,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            last_ids.second, t, request.visit_source);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the segment for this visit. KEYWORD_GENERATED visits should not
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // result in changing most visited, so we don't update segments (most
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // visited db).
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_keyword_generated) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateSegments(request.url, from_visit_id, last_ids.second, t,
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     request.time);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the referrer's duration.
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateVisitDuration(from_visit_id, request.time);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Redirect case. Add the redirect chain.
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition redirect_info =
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_CHAIN_START;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects = request.redirects;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (redirects[0].SchemeIs(chrome::kAboutScheme)) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the redirect source + referrer is "about" we skip it. This
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // happens when a page opens a new frame/window to about:blank and then
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // script sets the URL to somewhere else (used to hide the referrer). It
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would be nice to keep all these redirects properly but we don't ever
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // see the initial about:blank load, so we don't know where the
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // subsequent client redirect came from.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this case, we just don't bother hooking up the source of the
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects, so we remove it.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirects.erase(redirects.begin());
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The first entry in the redirect chain initiated a client redirect.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't add this to the database since the referrer is already
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // there, so we skip over it but change the transition type of the first
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transition to client redirect.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The referrer is invalid when restoring a session that features an
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // https tab that redirects to a different host or to http. In this
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case we don't need to reconnect the new redirect with the existing
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // chain.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (request.referrer.is_valid()) {
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(request.referrer == redirects[0]);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        redirects.erase(redirects.begin());
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the navigation entry for this visit has replaced that for the
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // first visit, remove the CHAIN_END marker from the first visit. This
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can be called a lot, for example, the page cycler, and most of the
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // time we won't have changed anything.
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisitRow visit_row;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (request.did_replace_entry &&
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db_->GetRowForVisit(last_ids.second, &visit_row) &&
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          visit_row.transition = content::PageTransitionFromInt(
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->UpdateVisitRow(visit_row);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t redirect_index = 0; redirect_index < redirects.size();
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         redirect_index++) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransition t =
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::PageTransitionFromInt(stripped_transition | redirect_info);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If this is the last transition, add a CHAIN_END marker
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (redirect_index == (redirects.size() - 1)) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t = content::PageTransitionFromInt(
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            t | content::PAGE_TRANSITION_CHAIN_END);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Record all redirect visits with the same timestamp. We don't display
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them anyway, and if we ever decide to, we can reconstruct their order
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the redirect chain.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_ids = AddPageVisit(redirects[redirect_index],
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              request.time, last_ids.second,
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              t, request.visit_source);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (t & content::PAGE_TRANSITION_CHAIN_START) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the segment for this visit.
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateSegments(redirects[redirect_index],
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       from_visit_id, last_ids.second, t, request.time);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the visit_details for this visit.
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateVisitDuration(from_visit_id, request.time);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Subsequent transitions in the redirect list must all be server
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // redirects.
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last, save this redirect chain for later so we can set titles & favicons
535bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // on the redirected pages properly.
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recent_redirects_.Put(request.url, redirects);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the last visit to the tracker so we can get outgoing transitions.
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation anyway, so last_visit_id is always zero for them.  But adding
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them here confuses main frame history, so we skip them for now.
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !is_keyword_generated) {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tracker_.AddVisit(request.id_scope, request.page_id, request.url,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      last_ids.second);
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::InitImpl(const std::string& languages) {
557b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!db_) << "Initializing HistoryBackend twice";
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the rare case where the db fails to initialize a dialog may get shown
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the blocks the caller, yet allows other messages through. For this reason
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only set db_ to the created database if creation is successful. That
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way other methods won't do anything as db_ is still NULL.
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Compute the file names.
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
5673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::FilePath thumbnail_name = GetFaviconsFileName();
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath archived_name = GetArchivedFileName();
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
570bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete the old index database files which are no longer used.
571bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DeleteFTSIndexDatabases();
572bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // History database.
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new HistoryDatabase());
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Unretained to avoid a ref loop with db_.
5777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  db_->set_error_callback(
5787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Bind(&HistoryBackend::DatabaseErrorCallback,
5797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                 base::Unretained(this)));
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  sql::InitStatus status = db_->Init(history_name);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_OK:
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::INIT_FAILURE: {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A NULL db_ will cause all calls on this object to notice this error
5877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // and to not continue. If the error callback scheduled killing the
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database, the task it posted has not executed yet. Try killing the
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // database now before we close it.
5907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      bool kill_db = scheduled_kill_db_;
5917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (kill_db)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        KillHistoryDatabase();
5937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->NotifyProfileError(id_, status);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the in-memory database and send it back to the history service on the
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // main thread.
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mem_backend->Init(history_name, db_.get()))
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->SetInMemoryBackend(id_, mem_backend);  // Takes ownership of
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      // pointer.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete mem_backend;  // Error case, run without the in-memory DB.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
612bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Create the history publisher which needs to be passed on to the thumbnail
613bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // database for publishing history.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_publisher_.reset(new HistoryPublisher());
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!history_publisher_->Init()) {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The init may fail when there are no indexers wanting our history.
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Hence no need to log the failure.
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history_publisher_.reset();
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Thumbnail database.
6223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): "thumbnail database" these days only stores
6233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // favicons.  Thumbnails are stored in "top sites".  Consider
6243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // renaming "thumbnail" references to "favicons" or something of the
6253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // sort.
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_.reset(new ThumbnailDatabase());
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thumbnail_db_->Init(thumbnail_name,
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          history_publisher_.get(),
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          db_.get()) != sql::INIT_OK) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unlike the main database, we don't error out when the database is too
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new because this error is much less severe. Generally, this shouldn't
63258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // happen since the thumbnail and main database versions should be in sync.
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We'll just continue without thumbnails & favicons in this case or any
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other error.
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the thumbnail database.";
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Archived database.
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->needs_version_17_migration()) {
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See needs_version_17_migration() decl for more. In this case, we want
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to delete the archived database and need to do so before we try to
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // open the file. We can ignore any error (maybe the file doesn't exist).
644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(archived_name);
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  archived_db_.reset(new ArchivedDatabase());
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!archived_db_->Init(archived_name)) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not initialize the archived database.";
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Generate the history and thumbnail database metrics only after performing
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any migration work.
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::RandInt(1, 100) == 50) {
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only do this computation sometimes since it can be expensive.
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->ComputeDatabaseMetrics(history_name);
6572385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (thumbnail_db_)
6582385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      thumbnail_db_->ComputeDatabaseMetrics();
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tell the expiration module about all the nice databases we made. This must
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // happen before db_->Init() is called since the callback ForceArchiveHistory
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may need to expire stuff.
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // *sigh*, this can all be cleaned up when that migration code is removed.
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The main DB initialization should intuitively be first (not that it
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // actually matters) and the expirer should be set last.
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.SetDatabases(db_.get(), archived_db_.get(),
669bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                        thumbnail_db_.get());
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the long-running transaction.
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
673b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
675b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the first item in our database.
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start expiring old stuff.
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
685b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    android_provider_backend_.reset(new AndroidProviderBackend(
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetAndroidCacheFileName(), db_.get(), thumbnail_db_.get(),
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bookmark_service_, delegate_.get()));
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HISTOGRAM_TIMES("History.InitTime",
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  TimeTicks::Now() - beginning_time);
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
696ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid HistoryBackend::OnMemoryPressure(
697ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
698ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool trim_aggressively = memory_pressure_level ==
699ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
700ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (db_)
701ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    db_->TrimMemory(trim_aggressively);
702ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (thumbnail_db_)
703ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    thumbnail_db_->TrimMemory(trim_aggressively);
704ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (archived_db_)
705ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    archived_db_->TrimMemory(trim_aggressively);
706ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
707ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloseAllDatabases() {
709b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the long-running transaction.
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->CommitTransaction();
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset();
71358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Forget the first recorded time since the database is closed.
71458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    first_recorded_time_ = base::Time();
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
716b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_.reset();
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
720b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time time,
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID referring_visit,
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitSource visit_source) {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Top-level frame navigations are visible, everything else is hidden
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool new_hidden = !content::PageTransitionIsMainFrame(transition);
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This code must stay in sync with
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExpireHistoryBackend::ExpireURLsForVisits().
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // typed, which would eliminate the need for this code.
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int typed_increment = 0;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::PageTransition transition_type =
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::PageTransitionStripQualifier(transition);
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((transition_type == content::PAGE_TRANSITION_TYPED &&
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !content::PageTransitionIsRedirect(transition)) ||
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typed_increment = 1;
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
748eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Only count the page visit if it came from user browsing and only count it
749eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // once when cycling through a redirect chain.
750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (visit_source == SOURCE_BROWSED &&
751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
752eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordTopPageVisitStats(url);
753eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
755eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if this URL is already in the DB.
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update of an existing row.
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::PageTransitionStripQualifier(transition) !=
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PAGE_TRANSITION_RELOAD)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_visit_count(url_info.visit_count() + 1);
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (typed_increment)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_typed_count(url_info.typed_count() + typed_increment);
766c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (url_info.last_visit() < time)
767c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_info.set_last_visit(time);
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only allow un-hiding of pages, never hiding.
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_hidden)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_info.set_hidden(false);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->UpdateURLRow(url_id, url_info);
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Addition of a new row.
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_visit_count(1);
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_typed_count(typed_increment);
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_last_visit(time);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_hidden(new_hidden);
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_id = db_->AddURL(url_info);
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Adding URL failed.";
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::make_pair(0, 0);
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.id_ = url_id;
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the visit with the time to the database.
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyVisitObservers(visit_info);
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_info.visit_time < first_recorded_time_)
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_recorded_time_ = visit_info.visit_time;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification of the visit.
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id) {
799b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
800b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
801b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLVisitedDetails* details = new URLVisitedDetails;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->transition = transition;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details->row = url_info;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(meelapshah) Disabled due to potential PageCycler regression.
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-enable this.
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // GetMostRecentRedirectsTo(url, &details->redirects);
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED, details);
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to build visit insert statement:  "
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << url_id;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::make_pair(url_id, visit_id);
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitSource visit_source) {
819b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!i->last_visit().is_null());
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We will add to either the archived database or the main one depending on
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the date of the added visit.
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLDatabase* url_database;
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitDatabase* visit_database;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsExpiredVisitTime(i->last_visit())) {
831b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      if (!archived_db_)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;  // No archived database to save it to, just forget this.
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = archived_db_.get();
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = archived_db_.get();
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_database = db_.get();
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_database = db_.get();
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow existing_url;
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID url_id = url_database->GetRowForURL(i->url(), &existing_url);
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_id) {
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the page if it doesn't exist.
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_id = url_database->AddURL(*i);
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_id) {
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Could not add row to DB";
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i->typed_count() > 0) {
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        modified->changed_urls.push_back(*i);
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        modified->changed_urls.back().set_id(url_id);  // *i likely has |id_| 0.
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync code manages the visits itself.
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_source != SOURCE_SYNCED) {
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make up a visit to correspond to the last visit to the page.
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit_info(url_id, i->last_visit(), 0,
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          content::PageTransitionFromInt(
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_LINK |
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_START |
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              content::PAGE_TRANSITION_CHAIN_END), 0);
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!visit_database->AddVisit(&visit_info, visit_source)) {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "Adding visit failed.";
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyVisitObservers(visit_info);
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visit_info.visit_time < first_recorded_time_)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_recorded_time_ = visit_info.visit_time;
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
876b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
877b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast a notification for typed URLs that have been modified. This
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be picked up by the in-memory URL database on the main thread.
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views can keep in sync.
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         modified.release());
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return time < expirer_.GetCurrentArchiveTime();
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetPageTitle(const GURL& url,
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const string16& title) {
895b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search for recent redirects which should get the same title. We make a
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dummy list containing the exact URL visited if there are no redirects so
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processing below can be the same.
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList dummy_list;
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList* redirects;
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(url);
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &iter->second;
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This redirect chain should have the destination URL as the last item.
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirects->empty());
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirects->back() == url);
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No redirect chain stored, make up one containing the URL we want so we
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // can use the same logic below.
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy_list.push_back(url);
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects = &dummy_list;
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirects->size(); i++) {
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (row_id && row.title() != title) {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row.set_title(title);
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->UpdateURLRow(row_id, row);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->changed_urls.push_back(row);
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast notifications for any URLs that have changed. This will
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the in-memory database and the InMemoryURLIndex.
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!details->changed_urls.empty()) {
931b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (typed_url_syncable_service_.get())
932b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           details.release());
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               const string16& title) {
941b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_info(url);
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id = db_->GetRowForURL(url, &url_info);
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_id) {
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL is already known, nothing to do.
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!title.empty()) {
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(title);
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_info.set_title(UTF8ToUTF16(url.spec()));
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_last_visit(Time::Now());
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the page hidden. If the user types it in, it'll unhide.
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_info.set_hidden(true);
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->AddURL(url_info);
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IterateURLs(
96590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iterator) {
967b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDatabase::URLEnumerator e;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->InitURLEnumeratorForEverything(&e)) {
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow info;
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (e.GetNextURL(&info)) {
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iterator->OnURL(info.url());
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterator->OnComplete(true);  // Success.
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iterator->OnComplete(false);  // Failure.
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
982b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetAllTypedUrls(urls);
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
988b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetVisitsForURL(id, visits);
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int max_visits,
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               VisitVector* visits) {
996b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
1002b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->UpdateURLRow(id, url);
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::AddVisits(const GURL& url,
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<VisitInfo>& visits,
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               VisitSource visit_source) {
1010b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         visit != visits.end(); ++visit) {
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!AddPageVisit(
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              url, visit->first, 0, visit->second, visit_source).first) {
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommit();
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1025b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.ExpireVisits(visits);
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VisitSourceMap* sources) {
1035b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetVisitsSource(visits, sources);
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1043b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return db_->GetRowForURL(url, url_row) != 0;
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryURL(scoped_refptr<QueryURLRequest> request,
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const GURL& url,
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool want_visits) {
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow* row = &request->value.a;
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector* visits = &request->value.b;
1057b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetRowForURL(url, row)) {
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Have a row.
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = true;
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Optionally query the visits.
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (want_visits)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetVisitsForURL(row->id(), visits);
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, row, visits);
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1070b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1071b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return typed_url_syncable_service_.get();
1072b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1073b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Segment usage ---------------------------------------------------------------
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteOldSegmentData() {
1077b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->DeleteSegmentData(Time::Now() -
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           TimeDelta::FromDays(kSegmentDataRetention));
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QuerySegmentUsage(
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Time from_time,
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_result_count) {
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1089b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this is the first time we query segments, invoke
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DeleteOldSegmentData asynchronously. We do this to cleanup old
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // entries.
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!segment_queried_) {
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      segment_queried_ = true;
109790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->PostTask(
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::IncreaseSegmentDuration(const GURL& url,
11062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::Time time,
11072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::TimeDelta delta) {
1108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string segment_name(VisitSegmentDatabase::ComputeSegmentName(url));
11122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SegmentID segment_id = db_->GetSegmentNamed(segment_name);
11132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!segment_id) {
11142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    URLID url_id = db_->GetRowForURL(url, NULL);
11152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!url_id)
11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
11172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    segment_id = db_->CreateSegment(url_id, segment_name);
11182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!segment_id)
11192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
11202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SegmentDurationID duration_id;
11222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta total_delta;
11232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_->GetSegmentDuration(segment_id, time, &duration_id,
11242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               &total_delta)) {
11252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->CreateSegmentDuration(segment_id, time, delta);
11262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  total_delta += delta;
11292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->SetSegmentDuration(duration_id, total_delta);
11302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QuerySegmentDuration(
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<QuerySegmentUsageRequest> request,
11342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time from_time,
11352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int max_result_count) {
11362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (request->canceled())
11372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1139b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QuerySegmentDuration(from_time, max_result_count,
11412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              &request->value.get());
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->ForwardResult(request->handle(), &request->value.get());
11442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keyword visits --------------------------------------------------------------
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 TemplateURLID keyword_id,
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 const string16& term) {
1151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the ID for this URL.
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRow url_row;
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->GetRowForURL(url, &url_row)) {
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a small possibility the url was deleted before the keyword
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was added. Ignore the request.
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->SetKeywordSearchTermsForURL(url_row.id(), keyword_id, term);
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // details is deleted by BroadcastNotifications.
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KeywordSearchTermDetails* details = new KeywordSearchTermDetails;
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->url = url;
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->keyword_id = keyword_id;
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->term = term;
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, details);
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllSearchTermsForKeyword(
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id) {
1176b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->DeleteAllSearchTermsForKeyword(keyword_id);
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky): bug 1168470. Need to move from archive dbs too.
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetMostRecentKeywordSearchTerms(
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLID keyword_id,
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& prefix,
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_count) {
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1192b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &(request->value));
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Downloads -------------------------------------------------------------------
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::GetNextDownloadId(uint32* next_id) {
1202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
12037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    db_->GetNextDownloadId(next_id);
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get all the download entries from the database.
12072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
12092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->QueryDownloads(rows);
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update a particular download entry.
12132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1214b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db_->UpdateDownload(data);
12172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::CreateDownload(const history::DownloadRow& history_info,
12217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    bool* success) {
1222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  *success = db_->CreateDownload(history_info);
12252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleCommit();
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1229b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
12302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_before = db_->CountDownloads();
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks started_removing = base::TimeTicks::Now();
12332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HistoryBackend uses a long-running Transaction that is committed
12342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // periodically, so this loop doesn't actually hit the disk too hard.
12357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::set<uint32>::const_iterator it = ids.begin();
12367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       it != ids.end(); ++it) {
12372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->RemoveDownload(*it);
12382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScheduleCommit();
12402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks finished_removing = base::TimeTicks::Now();
12417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t downloads_count_after = db_->CountDownloads();
12427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
12437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_LE(downloads_count_after, downloads_count_before);
12447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (downloads_count_after > downloads_count_before)
12457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
12477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
12487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        num_downloads_deleted);
12497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeDelta micros = (1000 * (finished_removing - started_removing));
12507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
12517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (num_downloads_deleted > 0) {
12527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
12537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        (1000 * micros) / num_downloads_deleted);
12542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GE(ids.size(), num_downloads_deleted);
12567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (ids.size() < num_downloads_deleted)
12577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
12587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
12597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        ids.size() - num_downloads_deleted);
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const string16& text_query,
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const QueryOptions& options) {
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (text_query.empty()) {
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Basic history query for the main database.
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Now query the archived database. This is a bit tricky because we don't
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // want to query it if the queried time range isn't going to find anything
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // in it.
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(brettw) bug 1171036: do blimpie querying for the archived database
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // as well.
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if (archived_db_.get() &&
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Text history query.
1284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      QueryHistoryText(db_.get(), db_.get(), text_query, options,
1285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                       &request->value);
1286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (archived_db_.get() &&
1287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          expirer_.GetCurrentArchiveTime() >= options.begin_time) {
1288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        QueryHistoryText(archived_db_.get(), archived_db_.get(), text_query,
1289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         options, &request->value);
1290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), &request->value);
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.QueryHistory",
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic time-based querying of history.
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       VisitDatabase* visit_db,
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const QueryOptions& options,
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QueryResults* result) {
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First get all visits.
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
13072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits);
13082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add them and the URL rows to the results.
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLResult url_result;
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); i++) {
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VisitRow visit = visits[i];
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add a result row for this visit, get the URL info from the DB.
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_db->GetURLRow(visit.url_id, &url_result)) {
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to get id " << visit.url_id
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " from history.urls.";
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // DB out of sync and URL doesn't exist, try to recover.
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!url_result.url().is_valid()) {
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Got invalid URL from history.urls with id "
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << visit.url_id << ":  "
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << url_result.url().possibly_invalid_spec();
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Don't report invalid URLs in case of corruption.
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The archived database may be out of sync with respect to starring,
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // titles, last visit date, etc. Therefore, we query the main DB if the
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // current URL database is not the main one.
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url_db == db_.get()) {
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Currently querying the archived DB, update with the main database to
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // catch any interesting stuff. This will update it if it exists in the
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // main DB, and do nothing otherwise.
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetRowForURL(url_result.url(), &url_result);
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_result.set_visit_time(visit.visit_time);
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Set whether the visit was blocked for a managed user by looking at the
1342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // transition type.
1343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    url_result.set_blocked_visit(
1344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't set any of the query-specific parts of the URLResult, since
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // snippets and stuff don't apply to basic querying.
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendURLBySwapping(&url_result);
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_more_results && options.begin_time <= first_recorded_time_)
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->set_reached_beginning(true);
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Text-based querying of history.
1356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::QueryHistoryText(URLDatabase* url_db,
1357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      VisitDatabase* visit_db,
1358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const string16& text_query,
1359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const QueryOptions& options,
1360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      QueryResults* result) {
1361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  URLRows text_matches;
1362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  url_db->GetTextMatches(text_query, &text_matches);
1363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<URLResult> matching_visits;
1365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  VisitVector visits;    // Declare outside loop to prevent re-construction.
1366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < text_matches.size(); i++) {
1367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const URLRow& text_match = text_matches[i];
1368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Get all visits for given URL match.
1369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    visit_db->GetVisitsForURLWithOptions(text_match.id(), options, &visits);
1370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < visits.size(); j++) {
1371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      URLResult url_result(text_match);
1372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_result.set_visit_time(visits[j].visit_time);
1373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      matching_visits.push_back(url_result);
1374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::sort(matching_visits.begin(), matching_visits.end(),
1378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            URLResult::CompareVisitTime);
1379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t max_results = options.max_count == 0 ?
1381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (std::vector<URLResult>::iterator it = matching_visits.begin();
1383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != matching_visits.end() && result->size() < max_results; ++it) {
1384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->AppendURLBySwapping(&(*it));
1385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (matching_visits.size() == result->size() &&
1388eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      options.begin_time <= first_recorded_time_)
1389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    result->set_reached_beginning(true);
1390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Frontend to GetMostRecentRedirectsFrom from the history thread.
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsFrom(
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsFrom(url, &request->value);
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryRedirectsTo(
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryRedirectsRequest> request,
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = GetMostRecentRedirectsTo(url, &request->value);
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), url, success, &request->value);
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetVisibleVisitCountToHost(
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<GetVisibleVisitCountToHostRequest> request,
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time first_visit;
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool success = db_.get() &&
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), success, count, first_visit);
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryTopURLsAndRedirects(
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count) {
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1429b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), false, NULL, NULL);
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL>* top_urls = &request->value.a;
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectMap* redirects = &request->value.b;
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_count, &data.get());
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_urls->push_back(data[i]->GetURL());
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*redirects)[top_urls->back()] = list;
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), true, top_urls, redirects);
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Will replace QueryTopURLsAndRedirectsRequest.
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLs(
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<QueryMostVisitedURLsRequest> request,
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_count,
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int days_back) {
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1459b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), MostVisitedURLList());
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MostVisitedURLList* result = &request->value;
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  QueryMostVisitedURLsImpl(result_count, days_back, result);
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), *result);
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryFilteredURLs(
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<QueryFilteredURLsRequest> request,
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int result_count,
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const history::VisitFilter& filter,
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool extended_info)  {
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time request_start = base::Time::Now();
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1480b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No History Database - return an empty list.
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult(request->handle(), FilteredURLList());
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitVector visits;
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, double> score_map;
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < visits.size(); ++i) {
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(georgey): experiment with visit_segment database granularity (it is
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently 24 hours) to use it directly instead of using visits database,
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is considerably slower.
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.reserve(score_map.size());
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<URLID, double>::iterator it = score_map.begin();
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != score_map.end(); ++it) {
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* pud = new PageUsageData(it->first);
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pud->SetScore(it->second);
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.push_back(pud);
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit to the top |result_count| results.
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(data.begin(), data.end(), PageUsageData::Predicate);
15082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_count && implicit_cast<int>(data.size()) > result_count)
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.resize(result_count);
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow info;
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_->GetURLRow(data[i]->GetID(), &info)) {
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetURL(info.url());
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data[i]->SetTitle(info.title());
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilteredURLList& result = request->value;
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilteredURL url(*current_data);
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extended_info) {
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitVector visits;
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetVisitsForURL(current_data->GetID(), &visits);
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits.size() > 0) {
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url.extended_info.total_visits = visits.size();
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < visits.size(); ++i) {
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url.extended_info.duration_opened +=
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              visits[i].visit_duration.InSeconds();
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (visits[i].visit_time > url.extended_info.last_visit_time) {
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url.extended_info.last_visit_time = visits[i].visit_time;
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(macourteau): implement the url.extended_info.visits stat.
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.push_back(url);
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta_time = std::max(1, std::min(999,
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATIC_HISTOGRAM_POINTER_BLOCK(
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NewTabPage.SuggestedSitesLoadTime",
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Add(delta_time),
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->ForwardResult(request->handle(), result);
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              int days_back,
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              MostVisitedURLList* result) {
1556b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<PageUsageData> data;
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->QuerySegmentUsage(base::Time::Now() -
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromDays(days_back),
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         result_count, &data.get());
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageUsageData* current_data = data[i];
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RedirectList redirects;
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back(url);
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsFromSpecificVisit(
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit, history::RedirectList* redirects) {
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow any redirects from the given visit and add them to the list.
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It *should* be impossible to get a circular chain here, but we check
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just in case to avoid infinite loops.
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetRedirectsToSpecificVisit(
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitID cur_visit,
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Follow redirects going to cur_visit. These are added to |redirects| in
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the order they are found. If a redirect chain looks like A -> B -> C and
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |cur_visit| = C, redirects will be {B, A} in that order.
1597b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL cur_url;
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<VisitID> visit_set;
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_set.insert(cur_visit);
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visit_set.find(cur_visit) != visit_set.end()) {
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Loop in visit chain, giving up";
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_set.insert(cur_visit);
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirects->push_back(cur_url);
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsFrom(
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& from_url,
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1617b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsFromSpecificVisit(cur_visit, redirects);
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetMostRecentRedirectsTo(
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& to_url,
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirects) {
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirects->clear();
1633b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cur_visit)
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No visits for URL.
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRedirectsToSpecificVisit(cur_visit, redirects);
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          HistoryURLProviderParams* params) {
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExecuteWithDB should handle the NULL database case.
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->ExecuteWithDB(this, db_.get(), params);
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1651bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid HistoryBackend::DeleteFTSIndexDatabases() {
1652bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Find files on disk matching the text databases file pattern so we can
1653bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // quickly test for and delete them.
1654bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath::StringType filepattern =
1655bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FILE_PATH_LITERAL("History Index *");
1656bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FileEnumerator enumerator(
1657bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      history_dir_, false, base::FileEnumerator::FILES, filepattern);
1658bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  int num_databases_deleted = 0;
1659bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::FilePath current_file;
1660bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  while (!(current_file = enumerator.Next()).empty()) {
1661bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (sql::Connection::Delete(current_file))
1662bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      num_databases_deleted++;
1663bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1664bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1665bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                       num_databases_deleted);
1666bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
1667bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFavicons(
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
16722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
167390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
16742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types,
16752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
16762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetFaviconsForURL(
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
16832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
168490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
16852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_results);
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconsFromDB(page_url, icon_types, desired_size_in_dip,
16872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    desired_scale_factors, bitmap_results);
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::GetFaviconForID(
169190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID favicon_id,
16922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int desired_size_in_dip,
16932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ScaleFactor desired_scale_factor,
169490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
169590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> favicon_ids;
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_ids.push_back(favicon_id);
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::ScaleFactor> desired_scale_factors;
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desired_scale_factors.push_back(desired_scale_factor);
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get results from DB.
17012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids,
17022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_size_in_dip,
17032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      desired_scale_factors,
17042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bitmap_results);
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetch(
17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
17122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
171390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
17142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
17152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    desired_size_in_dip, desired_scale_factors,
17162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bitmap_results);
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::MergeFavicon(
17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
17212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url,
172290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
1725b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::FaviconID favicon_id =
172990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!favicon_id) {
17322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is no favicon at |icon_url|, create it.
1733eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
17342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
17372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
17402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // replace it.
17412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bitmap_identical = false;
17422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool replaced_bitmap = false;
17432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
17442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes[i].pixel_size == pixel_size) {
17452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
17462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
17472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id_sizes[i].bitmap_id, base::Time::Now());
17482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bitmap_identical = true;
17492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
17502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
17512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_data, base::Time::Now());
17522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        replaced_bitmap = true;
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
17542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a vector of the pixel sizes of the favicon bitmaps currently at
17592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url|.
17602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
17612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
17622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!replaced_bitmap && !bitmap_identical) {
17652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set the preexisting favicon bitmaps as expired as the preexisting favicon
17662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmaps are not consistent with the merged in data.
17672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(favicon_id);
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delete an arbitrary favicon bitmap to avoid going over the limit of
17702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |kMaxFaviconBitmapsPerIconURL|.
17712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
17722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
17732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.erase(favicon_sizes.begin());
17742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
17752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
17762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    pixel_size);
17772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(pixel_size);
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A site may have changed the favicons that it uses for |page_url|.
17812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Example Scenario:
17822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   page_url = news.google.com
178358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //   Initial State: www.google.com/favicon.ico 16x16, 32x32
17842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
17852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //                ..., 16x16)
17862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulties:
17882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1. Sync requires that a call to GetFaviconsForURL() returns the
17892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    |bitmap_data| passed into MergeFavicon().
17902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
17912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      stay mapped to news.google.com because it would be unclear which 16x16
17922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //      bitmap should be returned via GetFaviconsForURL().
17932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2. www.google.com/favicon.ico may be mapped to more than just
17952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    news.google.com (eg www.google.com).
17962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
17972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
17982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // To resolve these problems, we copy all of the favicon bitmaps previously
17992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mapped to news.google.com (|page_url|) and add them to the favicon at
18002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
18012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |icon_url| are set to default to indicate that |icon_url| has incomplete
18022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // / incorrect data.
180358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
18042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //              news.google.com
18052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
18062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //               modified.
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<IconMapping> icon_mappings;
18092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
18122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
18132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i) {
18142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
18152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (icon_mappings[i].icon_url == icon_url)
18182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<FaviconBitmap> bitmaps_to_copy;
18212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
18222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     &bitmaps_to_copy);
18232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
18242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Do not add a favicon bitmap at a pixel size for which there is already
18252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // a favicon bitmap mapped to |icon_url|. The one there is more correct
18262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // and having multiple equally sized favicon bitmaps for |page_url| is
18272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ambiguous in terms of GetFaviconsForURL().
18282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
18292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
18302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != favicon_sizes.end())
18312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
18322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add the favicon bitmap as expired as it is not consistent with the
18342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // merged in data.
18352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->AddFaviconBitmap(favicon_id,
18362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].bitmap_data, base::Time(),
18372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bitmaps_to_copy[j].pixel_size);
18382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
18392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
18412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
18422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the favicon mappings such that only |icon_url| is mapped to
18462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |page_url|.
18472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool mapping_changed = false;
18482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
184990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconID> favicon_ids;
18502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_ids.push_back(favicon_id);
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
18522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mapping_changed = true;
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (mapping_changed || !bitmap_identical)
18562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFavicons(
18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
186290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
186390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data) {
1864b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ || !db_)
18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build map of FaviconBitmapData for each icon url.
187090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  typedef std::map<GURL, std::vector<chrome::FaviconBitmapData> >
18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BitmapDataByIconURL;
18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitmapDataByIconURL grouped_by_icon_url;
18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track whether the method modifies or creates any favicon bitmaps, favicons
18792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // or icon mappings.
18802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool data_modified = false;
18812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
188290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> icon_ids;
18832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
18842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != grouped_by_icon_url.end(); ++it) {
18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = it->first;
188690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID icon_id =
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
18882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!icon_id) {
18902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Remove the favicon sizes attribute from
18912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ThumbnailDatabase::AddFavicon().
1892eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
18932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_modified = true;
18942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_ids.push_back(icon_id);
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!data_modified)
18982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, &data_modified);
18992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
19002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetFaviconBitmaps(icon_id, it->second, NULL);
19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_modified |=
19042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_modified) {
19072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Send notification to the UI as an icon mapping, favicon, or favicon
19082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // bitmap was changed by this function.
19092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendFaviconChangedNotificationForPageAndRedirects(page_url);
19102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1917b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_ ||
19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &icon_mappings))
19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CloneFavicons(const GURL& old_page_url,
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& new_page_url) {
1931b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent cross-domain cloning.
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommit();
19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetImportedFavicons(
19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ImportedFaviconUsage>& favicon_usage) {
1944b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Track all URLs that had their favicons set or updated.
19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> favicons_changed;
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_usage.size(); i++) {
195390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL(
195490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        favicon_usage[i].favicon_url, chrome::FAVICON, NULL);
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_id) {
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This favicon doesn't exist yet, so we create it using the given data.
19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkotwicz): Pass in real pixel size.
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_id = thumbnail_db_->AddFavicon(
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_usage[i].favicon_url,
196090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          chrome::FAVICON,
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new base::RefCountedBytes(favicon_usage[i].png_data),
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          now,
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::Size());
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the mapping from all the URLs to the favicon.
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkService* bookmark_service = GetBookmarkService();
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url != favicon_usage[i].urls.end(); ++url) {
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URLRow url_row;
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!db_->GetRowForURL(*url, &url_row)) {
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the URL is present as a bookmark, add the url in history to
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // save the favicon mapping. This will match with what history db does
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for regular bookmarked URLs with favicons - when history db is
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // cleaned, we keep an entry in the db with 0 visits as long as that
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // url is bookmarked.
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (bookmark_service && bookmark_service_->IsBookmarked(*url)) {
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          URLRow url_info(*url);
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_visit_count(0);
19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_typed_count(0);
19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_last_visit(base::Time());
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_info.set_hidden(false);
19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_->AddURL(url_info);
19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
198890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!thumbnail_db_->GetIconMappingsForPageURL(
198990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                *url, chrome::FAVICON, NULL)) {
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // URL is present in history, update the favicon *only* if it is not
19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // set already.
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          thumbnail_db_->AddIconMapping(*url, favicon_id);
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicons_changed.insert(*url);
19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!favicons_changed.empty()) {
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the notification about the changed favicon URLs.
200190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    FaviconChangedDetails* changed_details = new FaviconChangedDetails;
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.swap(favicons_changed);
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           changed_details);
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* page_url,
20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& icon_urls,
20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
20132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
201490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |page_url| is specified, |icon_types| must be either a single icon
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type or icon types which are equivalent.
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!page_url ||
201890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == chrome::FAVICON ||
201990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == chrome::TOUCH_ICON ||
202090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == chrome::TOUCH_PRECOMPOSED_ICON ||
202190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         icon_types == (chrome::TOUCH_ICON | chrome::TOUCH_PRECOMPOSED_ICON));
20222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bitmap_results->clear();
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2024b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> favicon_ids;
20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The icon type for which the mappings will the updated and data will be
20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned.
203290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::IconType selected_icon_type = chrome::INVALID_ICON;
20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_urls.size(); ++i) {
20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url = icon_urls[i];
203690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type_out;
203790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const chrome::FaviconID favicon_id =
203890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        thumbnail_db_->GetFaviconIDForFaviconURL(
203990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            icon_url, icon_types, &icon_type_out);
20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_id) {
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Return and update icon mappings only for the largest icon type. As
20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if an |icon_url| with a larger icon type is found.
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out > selected_icon_type) {
20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_icon_type = icon_type_out;
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.clear();
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon_type_out == selected_icon_type)
20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        favicon_ids.push_back(favicon_id);
20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_url && !favicon_ids.empty()) {
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool mappings_updated =
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              favicon_ids);
20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappings_updated) {
20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendFaviconChangedNotificationForPageAndRedirects(*page_url);
20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommit();
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_size_in_dip,
20652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_scale_factors, bitmap_results);
20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SetFaviconBitmaps(
206990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconID icon_id,
207090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data,
20712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* favicon_bitmaps_changed) {
20722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_bitmaps_changed)
20732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *favicon_bitmaps_changed = false;
20742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconBitmapData> to_add = favicon_bitmap_data;
20792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
20812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
208290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapData>::iterator match_it = to_add.end();
208390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (std::vector<chrome::FaviconBitmapData>::iterator it = to_add.begin();
20842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != to_add.end(); ++it) {
20852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->pixel_size == pixel_size) {
20862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        match_it = it;
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
20922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (match_it == to_add.end()) {
20932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
20942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed)
20962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *favicon_bitmaps_changed = true;
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
20982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (favicon_bitmaps_changed &&
20992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !*favicon_bitmaps_changed &&
21002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
21012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
21022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            bitmap_id, base::Time::Now());
21032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
21042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
21052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Time::Now());
21062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (favicon_bitmaps_changed)
21082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *favicon_bitmaps_changed = true;
21092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
21102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      to_add.erase(match_it);
21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < to_add.size(); ++i) {
21152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
21162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time::Now(), to_add[i].pixel_size);
21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (favicon_bitmaps_changed)
21192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *favicon_bitmaps_changed = true;
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::ValidateSetFaviconsParams(
212490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data) const {
21252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<GURL, size_t> BitmapsPerIconURL;
21262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BitmapsPerIconURL num_bitmaps_per_icon_url;
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!favicon_bitmap_data[i].bitmap_data.get())
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& icon_url = favicon_bitmap_data[i].icon_url;
21322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!num_bitmaps_per_icon_url.count(icon_url))
21332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_bitmaps_per_icon_url[icon_url] = 1u;
21342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
21352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++num_bitmaps_per_icon_url[icon_url];
21362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
21372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
21392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
21422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != num_bitmaps_per_icon_url.end(); ++it) {
21432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->second > kMaxFaviconBitmapsPerIconURL)
21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool HistoryBackend::IsFaviconBitmapDataEqual(
21502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
21512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!new_bitmap_data.get())
21532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> original_bitmap_data;
21562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thumbnail_db_->GetFaviconBitmap(bitmap_id,
21572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL,
21582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  &original_bitmap_data,
21592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  NULL);
21602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_bitmap_data->Equals(original_bitmap_data);
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconsFromDB(
21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
216890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(favicon_bitmap_results);
21702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_bitmap_results->clear();
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_ || !thumbnail_db_)
21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Time the query.
21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks beginning_time = TimeTicks::Now();
21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get FaviconIDs for |page_url| and one of |icon_types|.
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &icon_mappings);
218290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> favicon_ids;
21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_mappings.size(); ++i)
21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ids.push_back(icon_mappings[i].icon_id);
21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate |favicon_bitmap_results| and |icon_url_sizes|.
21872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
21882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desired_size_in_dip, desired_scale_factors, favicon_bitmap_results);
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TimeTicks::Now() - beginning_time);
21912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success && !favicon_bitmap_results->empty();
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
219590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconID>& candidate_favicon_ids,
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int desired_size_in_dip,
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::ScaleFactor>& desired_scale_factors,
219890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_bitmap_results->clear();
22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_favicon_ids.empty())
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the FaviconID and the FaviconBitmapIDs which best match
22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |desired_size_in_dip| and |desired_scale_factors|.
22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Select bitmap results from multiple favicons once
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // content::FaviconStatus supports multiple icon URLs.
220890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::FaviconID best_favicon_id = 0;
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FaviconBitmapID> best_bitmap_ids;
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float highest_score = kSelectFaviconFramesInvalidScore;
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &bitmap_id_sizes);
22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build vector of gfx::Size from |bitmap_id_sizes|.
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<gfx::Size> sizes;
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizes.push_back(bitmap_id_sizes[j].pixel_size);
22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<size_t> candidate_bitmap_indices;
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score = 0;
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFaviconFrameIndices(sizes,
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_scale_factors,
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              desired_size_in_dip,
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &candidate_bitmap_indices,
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &score);
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (score > highest_score) {
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      highest_score = score;
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_favicon_id = candidate_favicon_ids[i],
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_bitmap_ids.clear();
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_t candidate_index = candidate_bitmap_indices[j];
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        best_bitmap_ids.push_back(
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bitmap_id_sizes[candidate_index].bitmap_id);
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct FaviconBitmapResults from |best_favicon_id| and
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |best_bitmap_ids|.
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
224390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  chrome::IconType icon_type;
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       &icon_type)) {
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time last_updated;
225190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::FaviconBitmapResult bitmap_result;
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_url = icon_url;
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.icon_type = icon_type;
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &last_updated,
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.bitmap_data,
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bitmap_result.pixel_size)) {
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_result.expired = (Time::Now() - last_updated) >
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromDays(kFaviconRefetchDays);
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bitmap_result.is_valid())
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
227190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
227290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconID>& icon_ids) {
2273b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_)
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find all the pages whose favicons we should set, we want to set it for
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the pages in the redirect chain if it redirected.
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirects;
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirects);
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save page <-> favicon associations.
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (history::RedirectList::const_iterator i(redirects.begin());
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != redirects.end(); ++i) {
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::SetFaviconMappingsForPage(
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
229390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::IconType icon_type,
229490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<chrome::FaviconID>& icon_ids) {
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool mappings_changed = false;
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two icon types are considered 'equivalent' if one of the icon types is
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the icon mappings from |page_url| for |icon_type| to the favicons
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |page_url| to favicons of a type equivalent to |icon_type| are removed.
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any favicons which are orphaned as a result of the removal of the
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon mappings.
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
230890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<chrome::FaviconID> unmapped_icon_ids = icon_ids;
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> icon_mappings;
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != icon_mappings.end(); ++m) {
231590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<chrome::FaviconID>::iterator icon_id_it = std::find(
23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the icon mapping already exists, avoid removing it and adding it back.
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_id_it != unmapped_icon_ids.end()) {
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unmapped_icon_ids.erase(icon_id_it);
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
232490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if ((icon_type == chrome::TOUCH_ICON &&
232590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         m->icon_type == chrome::TOUCH_PRECOMPOSED_ICON) ||
232690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        (icon_type == chrome::TOUCH_PRECOMPOSED_ICON &&
232790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         m->icon_type == chrome::TOUCH_ICON) || (icon_type == m->icon_type)) {
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail_db_->DeleteIconMapping(m->mapping_id);
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removing the icon mapping may have orphaned the associated favicon so
23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we must recheck it. This is not super fast, but this case will get
23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered rarely, since normally a page will always map to the same
23335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // favicon IDs. It will mostly happen for favicons we import.
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!thumbnail_db_->HasMappingFor(m->icon_id))
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        thumbnail_db_->DeleteFavicon(m->icon_id);
23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappings_changed = true;
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mappings_changed = true;
23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mappings_changed;
23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::GetCachedRecentRedirects(
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::RedirectList* redirect_list) {
23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != recent_redirects_.end()) {
23525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *redirect_list = iter->second;
23535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The redirect chain should have the destination URL as the last item.
23555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!redirect_list->empty());
23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(redirect_list->back() == page_url);
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No known redirects, construct mock redirect chain containing |page_url|.
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    redirect_list->push_back(page_url);
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url) {
23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::RedirectList redirect_list;
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetCachedRecentRedirects(page_url, &redirect_list);
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FaviconChangedDetails* changed_details = new FaviconChangedDetails;
23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < redirect_list.size(); ++i)
23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed_details->urls.insert(redirect_list[i]);
23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         changed_details);
23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::Commit() {
2377b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that a commit may not actually have been scheduled if a caller
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly calls this instead of using ScheduleCommit. Likewise, we
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // may reset the flag written by a pending commit. But this is OK! It
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will merely cause extra commits (which is kind of the idea). We
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could optimize more for this case (we may get two extra commits in
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some cases) but it hasn't been important yet.
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelScheduledCommit();
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2392b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (thumbnail_db_) {
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->CommitTransaction();
23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Somebody left a transaction open";
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2399b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->CommitTransaction();
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_->BeginTransaction();
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ScheduleCommit() {
2406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get())
24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduled_commit_ = new CommitLaterTask(this);
240990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::CancelScheduledCommit() {
2416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (scheduled_commit_.get()) {
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_->Cancel();
24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheduled_commit_ = NULL;
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTaskImpl() {
2423b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // db went away, release all the refs.
24255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReleaseDBTasks();
24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove any canceled tasks.
24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.front()->Release();
24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.pop_front();
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_task_requests_.empty())
24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the first task.
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryDBTaskRequest* request = db_task_requests_.front();
24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.pop_front();
24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->value->RunOnDBThread(this, db_.get())) {
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The task is done. Notify the callback.
24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->ForwardResult();
24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We AddRef'd the request before adding, need to release it now.
24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->Release();
24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tasks wants to run some more. Schedule it at the end of current tasks.
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_task_requests_.push_back(request);
24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // And process it after an invoke later.
244990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ReleaseDBTasks() {
24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::list<HistoryDBTaskRequest*>::iterator i =
24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*i)->Release();
24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.clear();
24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generic operations
24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURLs(urls);
24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteURL(const GURL& url) {
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expirer_.DeleteURL(url);
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a commit, if the user is deleting something for privacy reasons, we
24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to get it on disk ASAP.
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Commit();
24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ExpireHistoryBetween(
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& restrict_urls,
24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time begin_time,
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time end_time) {
249058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!db_)
249158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
249358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
249458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      restrict_urls.empty()) {
249558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Special case deleting all history so it can be faster and to reduce the
249658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // possibility of an information leak.
249758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DeleteAllHistory();
249858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
249958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Clearing parts of history, have the expirer do the depend
250058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
250158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
250258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Force a commit, if the user is deleting something for privacy reasons,
250358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // we want to get it on disk ASAP.
250458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Commit();
25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (begin_time <= first_recorded_time_)
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
25092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
25102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistoryForTimes(
25122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<base::Time>& times,
25132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time, base::Time end_time) {
2514b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (times.empty() || !db_)
25152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
25162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.begin() >= begin_time)
25182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Min time is before begin time: "
25192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
25202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(*times.rbegin() < end_time)
25212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Max time is after end time: "
25222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
25232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::QueryOptions options;
25252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.begin_time = begin_time;
25262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.end_time = end_time;
25272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
25282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryResults results;
25292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QueryHistoryBasic(db_.get(), db_.get(), options, &results);
25302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1st pass: find URLs that are visited at one of |times|.
25322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<GURL> urls;
25332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
25342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (times.count(results[i].visit_time()) > 0)
25352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      urls.insert(results[i].url());
25362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
25372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (urls.empty())
25382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
25392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 2nd pass: collect all visit times of those URLs.
25412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Time> times_to_expire;
25422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < results.size(); ++i) {
25432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (urls.count(results[i].url()))
25442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.push_back(results[i].visit_time());
25452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
25462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put the times in reverse chronological order and remove
25482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // duplicates (for expirer_.ExpireHistoryForTimes()).
25492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::sort(times_to_expire.begin(), times_to_expire.end(),
25502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            std::greater<base::Time>());
25512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  times_to_expire.erase(
25522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::unique(times_to_expire.begin(), times_to_expire.end()),
25532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      times_to_expire.end());
25542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expires by times and commit.
25562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!times_to_expire.empty());
25572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expirer_.ExpireHistoryForTimes(times_to_expire);
25582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Commit();
25592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(times_to_expire.back() >= first_recorded_time_);
25612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update |first_recorded_time_| if we expired it.
25622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (times_to_expire.back() == first_recorded_time_)
25632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_->GetStartDate(&first_recorded_time_);
25642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
25655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistoryBackend::ExpireHistory(
25672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<history::ExpireHistoryArgs>& expire_list) {
2568b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_) {
25692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_first_recorded_time = false;
25702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
25722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         expire_list.begin(); it != expire_list.end(); ++it) {
25732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
25745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it->begin_time < first_recorded_time_)
25762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        update_first_recorded_time = true;
25772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
25782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Commit();
25792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update |first_recorded_time_| if any deletion might have affected it.
25812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (update_first_recorded_time)
25822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_->GetStartDate(&first_recorded_time_);
25832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2587b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow url_row;
25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(*i, &url_row))
25935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // The URL isn't in the db; nothing to do.
25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector visits;
25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->GetVisitsForURL(url_row.id(), &visits);
25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visits.empty())
25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
26047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
26057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scheduled_kill_db_ = true;
26067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Don't just do the close/delete here, as we are being called by |db| and
26077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that seems dangerous.
26087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // TODO(shess): Consider changing KillHistoryDatabase() to use
26097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // RazeAndClose().  Then it can be cleared immediately.
26107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
26117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        FROM_HERE,
26127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::Bind(&HistoryBackend::KillHistoryDatabase, this));
26137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
26147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
26157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::KillHistoryDatabase() {
26177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scheduled_kill_db_ = false;
2618b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_)
26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rollback transaction because Raze() cannot be called from within a
26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RollbackTransaction();
26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = db_->Raze();
26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
26265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
26285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release AndroidProviderBackend before other objects.
26295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  android_provider_backend_.reset();
26305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
26315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expirer keeps tabs on the active databases. Tell it about the
26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // databases which will be closed.
2634bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  expirer_.SetDatabases(NULL, NULL, NULL);
26355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
26385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllDatabases();
26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::ProcessDBTask(
26425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<HistoryDBTaskRequest> request) {
2643868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(request.get());
26445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request->canceled())
26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool task_scheduled = !db_task_requests_.empty();
26485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we up the refcount of the request. ProcessDBTaskImpl will
26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release when done with the task.
26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->AddRef();
26515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_task_requests_.push_back(request.get());
26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!task_scheduled) {
26535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No other tasks are scheduled. Process request now.
26545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessDBTaskImpl();
26555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::BroadcastNotifications(
26595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
26605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryDetails* details_deleted) {
26615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate_| may be NULL if |this| is in the process of closing (closed by
2662b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // HistoryService -> HistoryBackend::Closing().
2663b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
26645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->BroadcastNotifications(type, details_deleted);
26655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete details_deleted;
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2669b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2670b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           bool archived,
2671b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                           URLRows* rows) {
2672b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (typed_url_syncable_service_.get())
2673b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    typed_url_syncable_service_->OnUrlsDeleted(all_history, archived, rows);
2674b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
2675b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deleting --------------------------------------------------------------------
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::DeleteAllHistory() {
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our approach to deleting all history is:
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  1. Copy the bookmarks and their dependencies to new tables with temporary
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     names.
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  2. Delete the original tables. Since tables can not share pages, we know
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     that any data we don't want to keep is now in an unused page.
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  3. Renaming the temporary tables to match the original.
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  4. Vacuuming the database to delete the unused pages.
26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we are likely to have very few bookmarks and their dependencies
26885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compared to all history, this is also much faster than just deleting from
26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original tables directly.
26905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bookmarked URLs.
26925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BookmarkService::URLAndTitle> starred_urls;
26935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkService* bookmark_service = GetBookmarkService();
26945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service)
26955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->GetBookmarks(&starred_urls);
26965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRows kept_urls;
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < starred_urls.size(); i++) {
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRow row;
27005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->GetRowForURL(starred_urls[i].url, &row))
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear the last visit time so when we write these rows they are "clean."
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_last_visit(Time());
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_visit_count(0);
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    row.set_typed_count(0);
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kept_urls.push_back(row);
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear thumbnail and favicon history. The favicons for the given URLs will
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be kept.
27123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClearAllThumbnailHistory(kept_urls)) {
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Thumbnail history could not be cleared";
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We continue in this error case. If the user wants to delete their
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // history, we should delete as much as we can.
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
271858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
271958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Therefore, we clear the list afterwards to make sure nobody uses this
272058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // invalid data.
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ClearAllMainHistory(kept_urls))
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Main history could not be cleared";
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kept_urls.clear();
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Delete archived history.
2726b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (archived_db_) {
27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Close the database and delete the file.
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset();
27292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath archived_file_name = GetArchivedFileName();
2730eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(archived_file_name);
27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now re-initialize the database (which may fail).
27335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archived_db_.reset(new ArchivedDatabase());
27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!archived_db_->Init(archived_file_name)) {
27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Could not initialize the archived database.";
27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_.reset();
27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Open our long-running transaction on this database.
27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      archived_db_->BeginTransaction();
27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
27415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
274558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Send out the notification that history is cleared. The in-memory database
27465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will pick this up and clear itself.
27475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLsDeletedDetails* details = new URLsDeletedDetails;
27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  details->all_history = true;
2749b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NotifySyncURLsDeleted(true, false, NULL);
27505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, details);
27515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2754b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!thumbnail_db_) {
27555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we have no reference to the thumbnail database, maybe there was an
27565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error opening it. In this case, we just try to blow it away to try to
27575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fix the error if it exists. This may fail, in which case either the
27585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file doesn't exist or there's no more we can do.
27593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sql::Connection::Delete(GetFaviconsFileName());
27603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
27613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Older version of the database.
2762eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(GetThumbnailFileName());
27635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
27645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Urls to retain mappings for.
27673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<GURL> urls_to_keep;
27683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin();
27693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != kept_urls.end(); ++i) {
27703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    urls_to_keep.push_back(i->url());
27713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
27725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Isolate from any long-running transaction.
27743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
27753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
27765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(shess): If this fails, perhaps the database should be razed
27783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // or deleted.
27793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
27803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->RollbackTransaction();
27813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    thumbnail_db_->BeginTransaction();
27823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
27835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
27855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
27865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
27875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avaliable in HistoryBackend.
27885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->ClearAndroidURLRows();
27895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
27905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to remove all the pages associated with the dropped tables. There
27925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must be no transaction open on the table when we do this. We assume that
27935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our long-running transaction is open, so we complete it and start it again.
27945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thumbnail_db_->transaction_nesting() == 1);
27955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->CommitTransaction();
27965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->Vacuum();
27975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thumbnail_db_->BeginTransaction();
27985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
27995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
28025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the duplicate URL table. We will copy the kept URLs into this.
28035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CreateTemporaryURLTable())
28045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
28055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
280658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Insert the URLs into the temporary table.
28075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
28085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
280958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    db_->AddTemporaryURL(*i);
28105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the original URL table with the temporary one.
28135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->CommitTemporaryURLTable())
28145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
28155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the old tables and recreate them empty.
28175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->RecreateAllTablesButURL();
28185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Vacuum to reclaim the space from the dropped tables. This must be done
28205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when there is no transaction open, and we assume that our long-running
28215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction is currently open.
28225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->CommitTransaction();
28235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->Vacuum();
28245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->BeginTransaction();
28255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_->GetStartDate(&first_recorded_time_);
28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
28285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkService* HistoryBackend::GetBookmarkService() {
28315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_service_)
28325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_service_->BlockTillLoaded();
28335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bookmark_service_;
28345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
28375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BriefVisitInfo info;
28385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.url_id = visit.url_id;
28395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.time = visit.visit_time;
28405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.transition = visit.transition;
28415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a delegate yet during setup or shutdown, we will drop
28425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these notifications.
2843b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (delegate_)
28445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->NotifyVisitDBObserversOnAddVisit(info);
28455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2847eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
2848eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::PopulateMostVisitedURLMap() {
2849eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MostVisitedURLList most_visited_urls;
2850eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
2851eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           &most_visited_urls);
2852eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2853eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2854eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2855eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    most_visited_urls_map_[most_visited_urls[i].url] = i;
2856eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2857eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2858eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2859eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2860eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2861eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2862eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rank = kPageVisitStatsMaxTopSites;
2863eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2864eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it != most_visited_urls_map_.end())
2865eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    rank = (*it).second;
2866eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2867eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            rank, kPageVisitStatsMaxTopSites + 1);
2868eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2869eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2870eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
28715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
2872