1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_backend.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <list>
872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <map>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
1072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <vector>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/compiler_specific.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_vector.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/metrics/histogram.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/history_url_provider.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_service.h"
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/history/download_create_info.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_notifications.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_publisher.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/in_memory_history_backend.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/page_usage_data.h"
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/history/top_sites.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/chromium_strings.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/registry_controlled_domain.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeTicks;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/* The HistoryBackend consists of a number of components:
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HistoryDatabase (stores past 3 months of history)
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLDatabase (stores a list of URLs)
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DownloadDatabase (stores a list of downloads)
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      VisitDatabase (stores a list of visits for the URLs)
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      VisitSegmentDatabase (stores groups of URLs for the most visited view).
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ArchivedDatabase (stores history older than 3 months)
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLDatabase (stores a list of URLs)
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DownloadDatabase (stores a list of downloads)
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      VisitDatabase (stores a list of visits for the URLs)
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (this does not store visit segments as they expire after 3 mos.)
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TextDatabaseManager (manages multiple text database for different times)
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TextDatabase (represents a single month of full-text index).
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ...more TextDatabase objects...
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExpireHistoryBackend (manages moving things from HistoryDatabase to
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          the ArchivedDatabase and deleting)
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch*/
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How long we keep segment data for in days. Currently 3 months.
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This value needs to be greater or equal to
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// dependency between MostVisitedModel and the history backend.
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kSegmentDataRetention = 90;
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of milliseconds we'll wait to do a commit, so that things are
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// batched together.
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kCommitIntervalMs = 10000;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The amount of time before we re-fetch the favicon.
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const int kFaviconRefetchDays = 7;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// GetSessionTabs returns all open tabs, or tabs closed kSessionCloseTimeWindow
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// seconds ago.
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kSessionCloseTimeWindowSecs = 10;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The maximum number of items we'll allow in the redirect list before
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// deleting some.
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kMaxRedirectCount = 32;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of days old a history entry can be before it is considered "old"
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// and is archived.
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kArchiveDaysThreshold = 90;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Converts from PageUsageData to MostVisitedURL. |redirects| is a
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// list of redirects for this URL. Empty list means no redirects.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochMostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const RedirectList& redirects) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MostVisitedURL mv;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  mv.url = page_data.GetURL();
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  mv.title = page_data.GetTitle();
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (redirects.empty()) {
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Redirects must contain at least the target url.
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mv.redirects.push_back(mv.url);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mv.redirects = redirects;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The last url must be the target url.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mv.redirects.push_back(mv.url);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return mv;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This task is run on a timer so that commits happen at regular intervals
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// so they are batched together. The important thing about this class is that
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// it supports canceling of the task so the reference to the backend will be
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// freed. The problem is that when history is shutting down, there is likely
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to be one of these commits still pending and holding a reference.
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The backend can call Cancel to have this task release the reference. The
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// task will still run (if we ever get to processing the event before
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// shutdown), but it will not do anything.
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Note that this is a refcounted object and is not a task in itself. It should
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// be assigned to a RunnableMethod.
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(brettw): bug 1165182: This should be replaced with a
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ScopedRunnableMethodFactory which will handle everything automatically (like
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we do in ExpireHistoryBackend).
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass CommitLaterTask : public base::RefCounted<CommitLaterTask> {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit CommitLaterTask(HistoryBackend* history_backend)
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : history_backend_(history_backend) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The backend will call this function if it is being destroyed so that we
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // release our reference.
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Cancel() {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history_backend_ = NULL;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RunCommit() {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (history_backend_.get())
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_backend_->Commit();
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  friend class base::RefCounted<CommitLaterTask>;
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~CommitLaterTask() {}
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<HistoryBackend> history_backend_;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles querying first the main database, then the full text database if that
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// fails. It will optionally keep track of all URLs seen so duplicates can be
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// eliminated. This is used by the querying sub-functions.
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(brettw): This class may be able to be simplified or eliminated. After
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// this was written, QueryResults can efficiently look up by URL, so the need
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// for this extra set of previously queried URLs is less important.
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass HistoryBackend::URLQuerier {
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLQuerier(URLDatabase* main_db, URLDatabase* archived_db, bool track_unique)
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : main_db_(main_db),
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        archived_db_(archived_db),
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        track_unique_(track_unique) {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When we're tracking unique URLs, returns true if this URL has been
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // previously queried. Only call when tracking unique URLs.
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool HasURL(const GURL& url) {
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(track_unique_);
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return unique_urls_.find(url) != unique_urls_.end();
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool GetRowForURL(const GURL& url, URLRow* row) {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!main_db_->GetRowForURL(url, row)) {
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!archived_db_ || !archived_db_->GetRowForURL(url, row)) {
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // This row is neither in the main nor the archived DB.
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (track_unique_)
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      unique_urls_.insert(url);
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLDatabase* main_db_;  // Guaranteed non-NULL.
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLDatabase* archived_db_;  // Possibly NULL.
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool track_unique_;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When track_unique_ is set, this is updated with every URL seen so far.
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<GURL> unique_urls_;
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(URLQuerier);
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// HistoryBackend --------------------------------------------------------------
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHistoryBackend::HistoryBackend(const FilePath& history_dir,
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               Delegate* delegate,
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               BookmarkService* bookmark_service)
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : delegate_(delegate),
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_dir_(history_dir),
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(expirer_(this, bookmark_service)),
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      recent_redirects_(kMaxRedirectCount),
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      backend_destroy_message_loop_(NULL),
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      backend_destroy_task_(NULL),
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      segment_queried_(false),
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bookmark_service_(bookmark_service) {
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHistoryBackend::~HistoryBackend() {
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!scheduled_commit_) << "Deleting without cleanup";
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ReleaseDBTasks();
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // First close the databases before optionally running the "destroy" task.
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Commit the long-running transaction.
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->CommitTransaction();
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_.reset();
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (thumbnail_db_.get()) {
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail_db_->CommitTransaction();
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail_db_.reset();
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (archived_db_.get()) {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_->CommitTransaction();
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_.reset();
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_database_.get()) {
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->CommitTransaction();
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_.reset();
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (backend_destroy_task_) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Notify an interested party (typically a unit test) that we're done.
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(backend_destroy_message_loop_);
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
244731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid HistoryBackend::Init(const std::string& languages, bool force_fail) {
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!force_fail)
246731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    InitImpl(languages);
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_->DBLoaded();
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::SetOnBackendDestroyTask(MessageLoop* message_loop,
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             Task* task) {
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (backend_destroy_task_) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DLOG(WARNING) << "Setting more than one destroy task, overriding";
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete backend_destroy_task_;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  backend_destroy_message_loop_ = message_loop;
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  backend_destroy_task_ = task;
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::Closing() {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Any scheduled commit will have a reference to us, we must make it
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // release that reference before we can be destroyed.
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CancelScheduledCommit();
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Release our reference to the delegate, this reference will be keeping the
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // history service alive.
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_.reset();
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::NotifyRenderProcessHostDestruction(const void* host) {
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tracker_.NotifyRenderProcessHostDestruction(host);
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath HistoryBackend::GetThumbnailFileName() const {
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return history_dir_.Append(chrome::kThumbnailsFilename);
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath HistoryBackend::GetFaviconsFileName() const {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return history_dir_.Append(chrome::kFaviconsFilename);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath HistoryBackend::GetArchivedFileName() const {
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return history_dir_.Append(chrome::kArchivedHistoryFilename);
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set is used to detect referrer loops.  Should not happen, but can
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // if the database is corrupt.
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<VisitID> visit_set;
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitID visit_id = from_visit;
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (visit_id) {
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitRow row;
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!db_->GetRowForVisit(visit_id, &row))
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return 0;
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (row.segment_id)
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return row.segment_id;  // Found a visit in this change with a segment.
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Check the referrer of this visit, if any.
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    visit_id = row.referring_visit;
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (visit_set.find(visit_id) != visit_set.end()) {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "Loop in referer chain, giving up";
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    visit_set.insert(visit_id);
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return 0;
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSegmentID HistoryBackend::UpdateSegments(const GURL& url,
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         VisitID from_visit,
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         VisitID visit_id,
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         PageTransition::Type transition_type,
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         const Time ts) {
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We only consider main frames.
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!PageTransition::IsMainFrame(transition_type))
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SegmentID segment_id = 0;
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PageTransition::Type t = PageTransition::StripQualifier(transition_type);
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Are we at the beginning of a new segment?
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (t == PageTransition::TYPED || t == PageTransition::AUTO_BOOKMARK) {
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If so, create or get the segment.
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string segment_name = db_->ComputeSegmentName(url);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLID url_id = db_->GetRowForURL(url, NULL);
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url_id)
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return 0;
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED();
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return 0;
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Note: if we update an existing segment, we update the url used to
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // represent that segment in order to minimize stale most visited
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // images.
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db_->UpdateSegmentRepresentationURL(segment_id, url_id);
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Note: it is possible there is no segment ID set for this visit chain.
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TYPED. (For example GENERATED). In this case this visit doesn't count
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // toward any segment.
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!(segment_id = GetLastSegmentID(from_visit)))
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return 0;
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set the segment in the visit.
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_->SetSegmentID(visit_id, segment_id)) {
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Finally, increase the counter for that segment / day.
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return segment_id;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Will be filled with the URL ID and the visit ID of the last addition.
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->id_scope, request->page_id, request->referrer));
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitID from_visit_id = last_ids.second;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If a redirect chain is given, we expect the last item in that chain to be
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the final URL.
379dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(request->redirects.empty() ||
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         request->redirects.back() == request->url);
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Avoid duplicating times in the database, at least as long as pages are
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // added in order. However, we don't want to disallow pages from recording
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // times earlier than our last_recorded_time_, because someone might set
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // their machine's clock back.
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (last_requested_time_ == request->time) {
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    last_recorded_time_ = last_recorded_time_ + TimeDelta::FromMicroseconds(1);
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    last_requested_time_ = request->time;
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    last_recorded_time_ = last_requested_time_;
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the user is adding older history, we need to make sure our times
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // are correct.
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->time < first_recorded_time_)
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    first_recorded_time_ = request->time;
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PageTransition::Type transition =
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PageTransition::StripQualifier(request->transition);
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool is_keyword_generated = (transition == PageTransition::KEYWORD_GENERATED);
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->redirects.size() <= 1) {
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The single entry is both a chain start and end.
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PageTransition::Type t = request->transition |
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PageTransition::CHAIN_START | PageTransition::CHAIN_END;
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No redirect case (one element means just the page itself).
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    last_ids = AddPageVisit(request->url, last_recorded_time_,
4093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                            last_ids.second, t, request->visit_source);
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Update the segment for this visit. KEYWORD_GENERATED visits should not
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // result in changing most visited, so we don't update segments (most
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // visited db).
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!is_keyword_generated) {
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UpdateSegments(request->url, from_visit_id, last_ids.second, t,
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     last_recorded_time_);
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Redirect case. Add the redirect chain.
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PageTransition::Type redirect_info = PageTransition::CHAIN_START;
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (request->redirects[0].SchemeIs(chrome::kAboutScheme)) {
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // When the redirect source + referrer is "about" we skip it. This
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // happens when a page opens a new frame/window to about:blank and then
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // script sets the URL to somewhere else (used to hide the referrer). It
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // would be nice to keep all these redirects properly but we don't ever
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // see the initial about:blank load, so we don't know where the
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // subsequent client redirect came from.
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // In this case, we just don't bother hooking up the source of the
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // redirects, so we remove it.
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->redirects.erase(request->redirects.begin());
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (request->transition & PageTransition::CLIENT_REDIRECT) {
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      redirect_info = PageTransition::CLIENT_REDIRECT;
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The first entry in the redirect chain initiated a client redirect.
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We don't add this to the database since the referrer is already
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // there, so we skip over it but change the transition type of the first
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // transition to client redirect.
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The referrer is invalid when restoring a session that features an
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // https tab that redirects to a different host or to http. In this
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // case we don't need to reconnect the new redirect with the existing
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // chain.
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (request->referrer.is_valid()) {
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK(request->referrer == request->redirects[0]);
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        request->redirects.erase(request->redirects.begin());
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // If the navigation entry for this visit has replaced that for the
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // first visit, remove the CHAIN_END marker from the first visit. This
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // can be called a lot, for example, the page cycler, and most of the
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // time we won't have changed anything.
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        VisitRow visit_row;
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (request->did_replace_entry &&
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            db_->GetRowForVisit(last_ids.second, &visit_row) &&
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            visit_row.transition | PageTransition::CHAIN_END) {
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          visit_row.transition &= ~PageTransition::CHAIN_END;
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          db_->UpdateVisitRow(visit_row);
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t redirect_index = 0; redirect_index < request->redirects.size();
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         redirect_index++) {
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PageTransition::Type t = transition | redirect_info;
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If this is the last transition, add a CHAIN_END marker
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (redirect_index == (request->redirects.size() - 1))
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        t = t | PageTransition::CHAIN_END;
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Record all redirect visits with the same timestamp. We don't display
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // them anyway, and if we ever decide to, we can reconstruct their order
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // from the redirect chain.
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      last_ids = AddPageVisit(request->redirects[redirect_index],
4753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              last_recorded_time_, last_ids.second,
4763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              t, request->visit_source);
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (t & PageTransition::CHAIN_START) {
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Update the segment for this visit.
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        UpdateSegments(request->redirects[redirect_index],
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       from_visit_id, last_ids.second, t, last_recorded_time_);
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Subsequent transitions in the redirect list must all be sever
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // redirects.
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      redirect_info = PageTransition::SERVER_REDIRECT;
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Last, save this redirect chain for later so we can set titles & favicons
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // on the redirected pages properly. It is indexed by the destination page.
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    recent_redirects_.Put(request->url, request->redirects);
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // views can keep in sync.
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add the last visit to the tracker so we can get outgoing transitions.
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // navigation anyway, so last_visit_id is always zero for them.  But adding
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // them here confuses main frame history, so we skip them for now.
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (transition != PageTransition::AUTO_SUBFRAME &&
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      transition != PageTransition::MANUAL_SUBFRAME && !is_keyword_generated) {
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tracker_.AddVisit(request->id_scope, request->page_id, request->url,
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      last_ids.second);
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_database_.get()) {
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->AddPageURL(request->url, last_ids.first, last_ids.second,
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               last_recorded_time_);
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommit();
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
514731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid HistoryBackend::InitImpl(const std::string& languages) {
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!db_.get()) << "Initializing HistoryBackend twice";
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // In the rare case where the db fails to initialize a dialog may get shown
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the blocks the caller, yet allows other messages through. For this reason
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we only set db_ to the created database if creation is successful. That
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // way other methods won't do anything as db_ is still NULL.
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeTicks beginning_time = TimeTicks::Now();
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Compute the file names. Note that the index file can be removed when the
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // text db manager is finished being hooked up.
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath thumbnail_name = GetThumbnailFileName();
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath archived_name = GetArchivedFileName();
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath tmp_bookmarks_file = history_dir_.Append(
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kHistoryBookmarksFileName);
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // History database.
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_.reset(new HistoryDatabase());
533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sql::InitStatus status = db_->Init(history_name, tmp_bookmarks_file);
534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  switch (status) {
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case sql::INIT_OK:
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case sql::INIT_FAILURE:
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // A NULL db_ will cause all calls on this object to notice this error
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // and to not continue.
540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delegate_->NotifyProfileError(status);
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db_.reset();
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Fill the in-memory database and send it back to the history service on the
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // main thread.
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
550dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (mem_backend->Init(history_name, history_dir_, db_.get(), languages))
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->SetInMemoryBackend(mem_backend);  // Takes ownership of pointer.
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete mem_backend;  // Error case, run without the in-memory DB.
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create the history publisher which needs to be passed on to the text and
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // thumbnail databases for publishing history.
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history_publisher_.reset(new HistoryPublisher());
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!history_publisher_->Init()) {
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The init may fail when there are no indexers wanting our history.
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Hence no need to log the failure.
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history_publisher_.reset();
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Full-text database. This has to be first so we can pass it to the
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // HistoryDatabase for migration.
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text_database_.reset(new TextDatabaseManager(history_dir_,
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               db_.get(), db_.get()));
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!text_database_->Init(history_publisher_.get())) {
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Text database initialization failed, running without it.";
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_.reset();
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_->needs_version_17_migration()) {
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See needs_version_17_migration() decl for more. In this case, we want
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // to erase all the text database files. This must be done after the text
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // database manager has been initialized, since it knows about all the
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // files it manages.
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->DeleteAll();
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Thumbnail database.
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail_db_.reset(new ThumbnailDatabase());
58372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!db_->GetNeedsThumbnailMigration()) {
5843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // No convertion needed - use new filename right away.
585513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    thumbnail_name = GetFaviconsFileName();
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (thumbnail_db_->Init(thumbnail_name,
588ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          history_publisher_.get(),
589ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          db_.get()) != sql::INIT_OK) {
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Unlike the main database, we don't error out when the database is too
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // new because this error is much less severe. Generally, this shouldn't
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // happen since the thumbnail and main datbase versions should be in sync.
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We'll just continue without thumbnails & favicons in this case or any
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // other error.
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Could not initialize the thumbnail database.";
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail_db_.reset();
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (db_->GetNeedsThumbnailMigration()) {
600513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "Starting TopSites migration";
601513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    delegate_->StartTopSitesMigration();
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Archived database.
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_->needs_version_17_migration()) {
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See needs_version_17_migration() decl for more. In this case, we want
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // to delete the archived database and need to do so before we try to
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // open the file. We can ignore any error (maybe the file doesn't exist).
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    file_util::Delete(archived_name, false);
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  archived_db_.reset(new ArchivedDatabase());
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!archived_db_->Init(archived_name)) {
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Could not initialize the archived database.";
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_.reset();
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Tell the expiration module about all the nice databases we made. This must
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // happen before db_->Init() is called since the callback ForceArchiveHistory
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // may need to expire stuff.
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // *sigh*, this can all be cleaned up when that migration code is removed.
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The main DB initialization should intuitively be first (not that it
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // actually matters) and the expirer should be set last.
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  expirer_.SetDatabases(db_.get(), archived_db_.get(),
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        thumbnail_db_.get(), text_database_.get());
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Open the long-running transaction.
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->BeginTransaction();
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (thumbnail_db_.get())
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail_db_->BeginTransaction();
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (archived_db_.get())
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_->BeginTransaction();
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_database_.get())
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->BeginTransaction();
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get the first item in our database.
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->GetStartDate(&first_recorded_time_);
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start expiring old stuff.
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HISTOGRAM_TIMES("History.InitTime",
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  TimeTicks::Now() - beginning_time);
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url,
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time time,
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitID referring_visit,
6503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PageTransition::Type transition,
6513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    VisitSource visit_source) {
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Top-level frame navigations are visible, everything else is hidden
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool new_hidden = !PageTransition::IsMainFrame(transition);
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: This code must stay in sync with
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ExpireHistoryBackend::ExpireURLsForVisits().
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // typed, which would eliminate the need for this code.
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int typed_increment = 0;
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PageTransition::Type transition_type =
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PageTransition::StripQualifier(transition);
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((transition_type == PageTransition::TYPED &&
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       !PageTransition::IsRedirect(transition)) ||
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      transition_type == PageTransition::KEYWORD_GENERATED)
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    typed_increment = 1;
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See if this URL is already in the DB.
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLRow url_info(url);
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLID url_id = db_->GetRowForURL(url, &url_info);
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url_id) {
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Update of an existing row.
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (PageTransition::StripQualifier(transition) != PageTransition::RELOAD)
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_info.set_visit_count(url_info.visit_count() + 1);
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (typed_increment)
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_info.set_typed_count(url_info.typed_count() + typed_increment);
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_info.set_last_visit(time);
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Only allow un-hiding of pages, never hiding.
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!new_hidden)
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_info.set_hidden(false);
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->UpdateURLRow(url_id, url_info);
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Addition of a new row.
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_info.set_visit_count(1);
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_info.set_typed_count(typed_increment);
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_info.set_last_visit(time);
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_info.set_hidden(new_hidden);
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_id = db_->AddURL(url_info);
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url_id) {
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "Adding URL failed.";
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return std::make_pair(0, 0);
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_info.id_ = url_id;
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We don't actually add the URL to the full text index at this point. It
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // might be nice to do this so that even if we get no title or body, the
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // user can search for URL components and get the page.
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // However, in most cases, we'll get at least a title and usually contents,
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // and this add will be redundant, slowing everything down. As a result,
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we ignore this edge case.
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add the visit with the time to the database.
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitRow visit_info(url_id, time, referring_visit, transition, 0);
7083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (visit_info.visit_time < first_recorded_time_)
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    first_recorded_time_ = visit_info.visit_time;
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Broadcast a notification of the visit.
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (visit_id) {
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLVisitedDetails* details = new URLVisitedDetails;
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    details->transition = transition;
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    details->row = url_info;
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(meelapshah) Disabled due to potential PageCycler regression.
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Re-enable this.
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // GetMostRecentRedirectsTo(url, &details->redirects);
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BroadcastNotifications(NotificationType::HISTORY_URL_VISITED, details);
72272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
72372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    VLOG(0) << "Failed to build visit insert statement:  "
72472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            << "url_id = " << url_id;
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return std::make_pair(url_id, visit_id);
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HistoryBackend::AddPagesWithDetails(const std::vector<URLRow>& urls,
7313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                         VisitSource visit_source) {
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<URLRow>::const_iterator i = urls.begin();
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != urls.end(); ++i) {
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(!i->last_visit().is_null());
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We will add to either the archived database or the main one depending on
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the date of the added visit.
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLDatabase* url_database;
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitDatabase* visit_database;
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (i->last_visit() < expirer_.GetCurrentArchiveTime()) {
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!archived_db_.get())
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;  // No archived database to save it to, just forget this.
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_database = archived_db_.get();
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      visit_database = archived_db_.get();
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_database = db_.get();
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      visit_database = db_.get();
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLRow existing_url;
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLID url_id = url_database->GetRowForURL(i->url(), &existing_url);
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url_id) {
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Add the page if it doesn't exist.
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_id = url_database->AddURL(*i);
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!url_id) {
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED() << "Could not add row to DB";
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (i->typed_count() > 0)
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        modified->changed_urls.push_back(*i);
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Add the page to the full text index. This function is also used for
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // importing. Even though we don't have page contents, we can at least
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // add the title and URL to the index so they can be searched. We don't
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // bother to delete any already-existing FTS entries for the URL, since
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // this is normally called on import.
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If you ever import *after* first run (selecting import from the menu),
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // then these additional entries will "shadow" the originals when querying
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // for the most recent match only, and the user won't get snippets. This is
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // a very minor issue, and fixing it will make import slower, so we don't
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // bother.
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool has_indexed = false;
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (text_database_.get()) {
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We do not have to make it update the visit database, below, we will
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // create the visit entry with the indexed flag set.
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      has_indexed = text_database_->AddPageData(i->url(), url_id, 0,
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                i->last_visit(),
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                i->title(), string16());
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Make up a visit to correspond to that page.
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitRow visit_info(url_id, i->last_visit(), 0,
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PageTransition::LINK | PageTransition::CHAIN_START |
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PageTransition::CHAIN_END, 0);
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    visit_info.is_indexed = has_indexed;
7933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!visit_database->AddVisit(&visit_info, visit_source)) {
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "Adding visit failed.";
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (visit_info.visit_time < first_recorded_time_)
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      first_recorded_time_ = visit_info.visit_time;
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Broadcast a notification for typed URLs that have been modified. This
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will be picked up by the in-memory URL database on the main thread.
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(brettw) bug 1140015: Add an "add page" notification so the history
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // views can keep in sync.
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BroadcastNotifications(NotificationType::HISTORY_TYPED_URLS_MODIFIED,
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         modified.release());
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommit();
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::SetPageTitle(const GURL& url,
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const string16& title) {
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Search for recent redirects which should get the same title. We make a
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // dummy list containing the exact URL visited if there are no redirects so
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the processing below can be the same.
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history::RedirectList dummy_list;
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history::RedirectList* redirects;
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RedirectCache::iterator iter = recent_redirects_.Get(url);
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (iter != recent_redirects_.end()) {
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    redirects = &iter->second;
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This redirect chain should have the destination URL as the last item.
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(!redirects->empty());
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(redirects->back() == url);
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No redirect chain stored, make up one containing the URL we want so we
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // can use the same logic below.
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dummy_list.push_back(url);
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    redirects = &dummy_list;
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool typed_url_changed = false;
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<URLRow> changed_urls;
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < redirects->size(); i++) {
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLRow row;
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (row_id && row.title() != title) {
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      row.set_title(title);
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db_->UpdateURLRow(row_id, row);
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      changed_urls.push_back(row);
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (row.typed_count() > 0)
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        typed_url_changed = true;
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Broadcast notifications for typed URLs that have changed. This will
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // update the in-memory database.
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(brettw) bug 1140020: Broadcast for all changes (not just typed),
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in which case some logic can be removed.
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (typed_url_changed) {
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLsModifiedDetails* modified =
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new URLsModifiedDetails;
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < changed_urls.size(); i++) {
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (changed_urls[i].typed_count() > 0)
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        modified->changed_urls.push_back(changed_urls[i]);
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BroadcastNotifications(NotificationType::HISTORY_TYPED_URLS_MODIFIED,
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           modified);
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update the full text index.
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_database_.get())
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->AddPageTitle(url, title);
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only bother committing if things changed.
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!changed_urls.empty())
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleCommit();
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid HistoryBackend::AddPageNoVisitForBookmark(const GURL& url) {
87721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!db_.get())
87821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
87921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
88021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  URLRow url_info(url);
88121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  URLID url_id = db_->GetRowForURL(url, &url_info);
88221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (url_id) {
88321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // URL is already known, nothing to do.
88421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
88521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
88621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  url_info.set_last_visit(Time::Now());
88721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Mark the page hidden. If the user types it in, it'll unhide.
88821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  url_info.set_hidden(true);
88921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
89021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  db_->AddURL(url_info);
89121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
89221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::IterateURLs(HistoryService::URLEnumerator* iterator) {
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HistoryDatabase::URLEnumerator e;
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (db_->InitURLEnumeratorForEverything(&e)) {
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLRow info;
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      while (e.GetNextURL(&info)) {
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        iterator->OnURL(info.url());
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      iterator->OnComplete(true);  // Success.
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  iterator->OnComplete(false);  // Failure.
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::GetAllTypedURLs(std::vector<history::URLRow>* urls) {
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return db_->GetAllTypedUrls(urls);
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return db_->GetVisitsForURL(id, visits);
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return db_->UpdateURLRow(id, url);
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::AddVisits(const GURL& url,
9273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                               const std::vector<base::Time>& visits,
9283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                               VisitSource visit_source) {
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::vector<base::Time>::const_iterator visit = visits.begin();
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         visit != visits.end(); ++visit) {
9323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (!AddPageVisit(url, *visit, 0, 0, visit_source).first) {
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleCommit();
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::RemoveVisits(const VisitVector& visits) {
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::map<URLID, int> url_visits_removed;
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (VisitVector::const_iterator visit = visits.begin();
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         visit != visits.end(); ++visit) {
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db_->DeleteVisit(*visit);
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::map<URLID, int>::iterator visit_count =
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          url_visits_removed.find(visit->url_id);
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (visit_count == url_visits_removed.end()) {
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        url_visits_removed[visit->url_id] = 1;
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ++visit_count->second;
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::map<URLID, int>::iterator count = url_visits_removed.begin();
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         count != url_visits_removed.end(); ++count) {
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history::URLRow url_row;
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!db_->GetURLRow(count->first, &url_row)) {
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK(count->second <= url_row.visit_count());
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_row.set_visit_count(url_row.visit_count() - count->second);
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!db_->UpdateURLRow(url_row.id(), url_row)) {
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleCommit();
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return db_->GetRowForURL(url, url_row) != 0;
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryURL(scoped_refptr<QueryURLRequest> request,
981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              const GURL& url,
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              bool want_visits) {
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = false;
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLRow* row = &request->value.a;
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitVector* visits = &request->value.b;
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (db_->GetRowForURL(url, row)) {
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Have a row.
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      success = true;
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Optionally query the visits.
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (want_visits)
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        db_->GetVisitsForURL(row->id(), visits);
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(QueryURLRequest::TupleType(request->handle(), success,
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                    row, visits));
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Segment usage ---------------------------------------------------------------
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::DeleteOldSegmentData() {
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->DeleteSegmentData(Time::Now() -
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           TimeDelta::FromDays(kSegmentDataRetention));
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::SetSegmentPresentationIndex(SegmentID segment_id,
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 int index) {
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->SetSegmentPresentationIndex(segment_id, index);
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QuerySegmentUsage(
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<QuerySegmentUsageRequest> request,
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const Time from_time,
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int max_result_count) {
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If this is the first time we query segments, invoke
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // DeleteOldSegmentData asynchronously. We do this to cleanup old
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // entries.
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!segment_queried_) {
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      segment_queried_ = true;
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MessageLoop::current()->PostTask(FROM_HERE,
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewRunnableMethod(this, &HistoryBackend::DeleteOldSegmentData));
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      QuerySegmentUsageRequest::TupleType(request->handle(),
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          &request->value.get()));
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Keyword visits --------------------------------------------------------------
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
10443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                 TemplateURLID keyword_id,
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 const string16& term) {
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get the ID for this URL.
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLRow url_row;
1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_->GetRowForURL(url, &url_row)) {
1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // There is a small possibility the url was deleted before the keyword
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // was added. Ignore the request.
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->SetKeywordSearchTermsForURL(url_row.id(), keyword_id, term);
1058513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
1059513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // details is deleted by BroadcastNotifications.
1060513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  KeywordSearchTermDetails* details = new KeywordSearchTermDetails;
1061513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  details->url = url;
1062513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  details->keyword_id = keyword_id;
1063513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  details->term = term;
1064513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  BroadcastNotifications(NotificationType::HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1065513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                         details);
1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommit();
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::DeleteAllSearchTermsForKeyword(
10703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    TemplateURLID keyword_id) {
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->DeleteAllSearchTermsForKeyword(keyword_id);
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(sky): bug 1168470. Need to move from archive dbs too.
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommit();
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::GetMostRecentKeywordSearchTerms(
1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
10813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    TemplateURLID keyword_id,
1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const string16& prefix,
1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int max_count) {
1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         &(request->value));
1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(
1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetMostRecentKeywordSearchTermsRequest::TupleType(request->handle(),
1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                        &request->value));
1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Downloads -------------------------------------------------------------------
1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Get all the download entries from the database.
1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryDownloads(
1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<DownloadQueryRequest> request) {
1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->QueryDownloads(&request->value);
1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(DownloadQueryRequest::TupleType(&request->value));
1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Clean up entries that has been corrupted (because of the crash, for example).
1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::CleanUpInProgressEntries() {
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If some "in progress" entries were not updated when Chrome exited, they
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // need to be cleaned up.
1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->CleanUpInProgressEntries();
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Update a particular download entry.
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::UpdateDownload(int64 received_bytes,
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    int32 state,
1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    int64 db_handle) {
1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->UpdateDownload(received_bytes, state, db_handle);
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Update the path of a particular download entry.
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::UpdateDownloadPath(const FilePath& path,
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        int64 db_handle) {
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->UpdateDownloadPath(path, db_handle);
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Create a new download entry and pass back the db_handle to it.
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::CreateDownload(
1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<DownloadCreateRequest> request,
1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const DownloadCreateInfo& create_info) {
1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 db_handle = 0;
1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!request->canceled()) {
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (db_.get())
1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db_handle = db_->CreateDownload(create_info);
1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->ForwardResult(DownloadCreateRequest::TupleType(create_info,
1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                            db_handle));
1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::RemoveDownload(int64 db_handle) {
1146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->RemoveDownload(db_handle);
1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::RemoveDownloadsBetween(const Time remove_begin,
1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            const Time remove_end) {
1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get())
1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->RemoveDownloadsBetween(remove_begin, remove_end);
1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const string16& text_query,
1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const QueryOptions& options) {
1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeTicks beginning_time = TimeTicks::Now();
1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (text_query.empty()) {
1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Basic history query for the main database.
1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Now query the archived database. This is a bit tricky because we don't
1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // want to query it if the queried time range isn't going to find anything
1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // in it.
1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(brettw) bug 1171036: do blimpie querying for the archived database
1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // as well.
1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // if (archived_db_.get() &&
1175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Full text history query.
1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      QueryHistoryFTS(text_query, options, &request->value);
1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(QueryHistoryRequest::TupleType(request->handle(),
1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                        &request->value));
1184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES("History.QueryHistory",
1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      TimeTicks::Now() - beginning_time);
1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Basic time-based querying of history.
1190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       VisitDatabase* visit_db,
1192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const QueryOptions& options,
1193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       QueryResults* result) {
1194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // First get all visits.
1195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitVector visits;
1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visit_db->GetVisibleVisitsInRange(options.begin_time, options.end_time,
1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    options.max_count, &visits);
1198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(options.max_count == 0 ||
1199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         static_cast<int>(visits.size()) <= options.max_count);
1200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now add them and the URL rows to the results.
1202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLResult url_result;
1203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < visits.size(); i++) {
1204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const VisitRow visit = visits[i];
1205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Add a result row for this visit, get the URL info from the DB.
120772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!url_db->GetURLRow(visit.url_id, &url_result)) {
120872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      VLOG(0) << "Failed to get id " << visit.url_id
120972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              << " from history.urls.";
1210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;  // DB out of sync and URL doesn't exist, try to recover.
121172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
121272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
121372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!url_result.url().is_valid()) {
121472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      VLOG(0) << "Got invalid URL from history.urls with id "
121572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              << visit.url_id << ":  "
121672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              << url_result.url().possibly_invalid_spec();
1217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;  // Don't report invalid URLs in case of corruption.
121872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
1219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The archived database may be out of sync with respect to starring,
1221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // titles, last visit date, etc. Therefore, we query the main DB if the
1222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // current URL database is not the main one.
1223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (url_db == db_.get()) {
1224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Currently querying the archived DB, update with the main database to
1225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // catch any interesting stuff. This will update it if it exists in the
1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // main DB, and do nothing otherwise.
1227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db_->GetRowForURL(url_result.url(), &url_result);
1228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_result.set_visit_time(visit.visit_time);
1231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We don't set any of the query-specific parts of the URLResult, since
1233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // snippets and stuff don't apply to basic querying.
1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->AppendURLBySwapping(&url_result);
1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (options.begin_time <= first_recorded_time_)
1238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->set_reached_beginning(true);
1239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryHistoryFTS(const string16& text_query,
1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const QueryOptions& options,
1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     QueryResults* result) {
1244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!text_database_.get())
1245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Full text query, first get all the FTS results in the time range.
1248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<TextDatabase::Match> fts_matches;
1249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time first_time_searched;
1250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text_database_->GetTextMatches(text_query, options,
1251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 &fts_matches, &first_time_searched);
1252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLQuerier querier(db_.get(), archived_db_.get(), true);
1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now get the row and visit information for each one.
1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLResult url_result;  // Declare outside loop to prevent re-construction.
1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < fts_matches.size(); i++) {
1258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (options.max_count != 0 &&
1259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        static_cast<int>(result->size()) >= options.max_count)
1260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;  // Got too many items.
1261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Get the URL, querying the main and archived databases as necessary. If
1263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // this is not found, the history and full text search databases are out
1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // of sync and we give up with this result.
1265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!querier.GetRowForURL(fts_matches[i].url, &url_result))
1266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
1267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url_result.url().is_valid())
1269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;  // Don't report invalid URLs in case of corruption.
1270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Copy over the FTS stuff that the URLDatabase doesn't know about.
1272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We do this with swap() to avoid copying, since we know we don't
1273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // need the original any more. Note that we override the title with the
1274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // one from FTS, since that will match the title_match_positions (the
1275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // FTS title and the history DB title may differ).
1276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_result.set_title(fts_matches[i].title);
1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_result.title_match_positions_.swap(
1278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        fts_matches[i].title_match_positions);
1279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_result.snippet_.Swap(&fts_matches[i].snippet);
1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The visit time also comes from the full text search database. Since it
1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // has the time, we can avoid an extra query of the visits table.
1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_result.set_visit_time(fts_matches[i].time);
1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Add it to the vector, this will clear our |url_row| object as a
1286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // result of the swap.
1287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->AppendURLBySwapping(&url_result);
1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (options.begin_time <= first_recorded_time_)
1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->set_reached_beginning(true);
1292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Frontend to GetMostRecentRedirectsFrom from the history thread.
1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryRedirectsFrom(
1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<QueryRedirectsRequest> request,
1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url) {
1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = GetMostRecentRedirectsFrom(url, &request->value);
1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(QueryRedirectsRequest::TupleType(
1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->handle(), url, success, &request->value));
1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryRedirectsTo(
1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<QueryRedirectsRequest> request,
1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url) {
1308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = GetMostRecentRedirectsTo(url, &request->value);
1311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(QueryRedirectsRequest::TupleType(
1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->handle(), url, success, &request->value));
1313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::GetVisitCountToHost(
1316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<GetVisitCountToHostRequest> request,
1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url) {
1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int count = 0;
1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time first_visit;
1322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool success = (db_.get() && db_->GetVisitCountToHost(url, &count,
1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                              &first_visit));
1324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(GetVisitCountToHostRequest::TupleType(
1325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->handle(), success, count, first_visit));
1326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryTopURLsAndRedirects(
1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
1330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int result_count) {
1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get()) {
1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->ForwardResult(QueryTopURLsAndRedirectsRequest::TupleType(
1336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        request->handle(), false, NULL, NULL));
1337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<GURL>* top_urls = &request->value.a;
1341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history::RedirectMap* redirects = &request->value.b;
1342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedVector<PageUsageData> data;
1344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
1345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      result_count, &data.get());
1346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < data.size(); ++i) {
1348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    top_urls->push_back(data[i]->GetURL());
1349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
1350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
1351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*redirects)[top_urls->back()] = list;
1352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(QueryTopURLsAndRedirectsRequest::TupleType(
1355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->handle(), true, top_urls, redirects));
1356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Will replace QueryTopURLsAndRedirectsRequest.
1359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::QueryMostVisitedURLs(
1360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<QueryMostVisitedURLsRequest> request,
1361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int result_count,
1362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int days_back) {
1363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get()) {
1367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No History Database - return an empty list.
1368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->ForwardResult(QueryMostVisitedURLsRequest::TupleType(
1369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        request->handle(), MostVisitedURLList()));
1370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MostVisitedURLList* result = &request->value;
1374513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  QueryMostVisitedURLsImpl(result_count, days_back, result);
1375513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  request->ForwardResult(QueryMostVisitedURLsRequest::TupleType(
1376513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      request->handle(), *result));
1377513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
1378513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
1379513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
1380513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                              int days_back,
1381513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                              MostVisitedURLList* result) {
1382513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!db_.get())
1383513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
1384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedVector<PageUsageData> data;
1386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->QuerySegmentUsage(base::Time::Now() -
1387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         base::TimeDelta::FromDays(days_back),
1388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         result_count, &data.get());
1389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < data.size(); ++i) {
1391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PageUsageData* current_data = data[i];
1392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RedirectList redirects;
1393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
1394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
1395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->push_back(url);
1396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::GetRedirectsFromSpecificVisit(
1400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitID cur_visit, history::RedirectList* redirects) {
1401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Follow any redirects from the given visit and add them to the list.
1402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // It *should* be impossible to get a circular chain here, but we check
1403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // just in case to avoid infinite loops.
1404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL cur_url;
1405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<VisitID> visit_set;
1406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visit_set.insert(cur_visit);
1407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
1408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (visit_set.find(cur_visit) != visit_set.end()) {
1409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "Loop in visit chain, giving up";
1410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
1411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    visit_set.insert(cur_visit);
1413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    redirects->push_back(cur_url);
1414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::GetRedirectsToSpecificVisit(
1418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitID cur_visit,
1419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::RedirectList* redirects) {
1420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Follow redirects going to cur_visit. These are added to |redirects| in
1421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the order they are found. If a redirect chain looks like A -> B -> C and
1422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |cur_visit| = C, redirects will be {B, A} in that order.
1423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
1424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL cur_url;
1427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<VisitID> visit_set;
1428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visit_set.insert(cur_visit);
1429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
1430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (visit_set.find(cur_visit) != visit_set.end()) {
1431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "Loop in visit chain, giving up";
1432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
1433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    visit_set.insert(cur_visit);
1435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    redirects->push_back(cur_url);
1436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::GetMostRecentRedirectsFrom(
1440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& from_url,
1441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::RedirectList* redirects) {
1442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  redirects->clear();
1443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
1444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLID from_url_id = db_->GetRowForURL(from_url, NULL);
1447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
1448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!cur_visit)
1449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;  // No visits for URL.
1450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetRedirectsFromSpecificVisit(cur_visit, redirects);
1452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::GetMostRecentRedirectsTo(
1456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& to_url,
1457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::RedirectList* redirects) {
1458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  redirects->clear();
1459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
1460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLID to_url_id = db_->GetRowForURL(to_url, NULL);
1463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
1464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!cur_visit)
1465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;  // No visits for URL.
1466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetRedirectsToSpecificVisit(cur_visit, redirects);
1468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          HistoryURLProviderParams* params) {
1473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ExecuteWithDB should handle the NULL database case.
1474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  provider->ExecuteWithDB(this, db_.get(), params);
1475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::SetPageContents(const GURL& url,
1478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const string16& contents) {
1479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is histogrammed in the text database manager.
1480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!text_database_.get())
1481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text_database_->AddPageContents(url, contents);
1483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::SetPageThumbnail(
1486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url,
1487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SkBitmap& thumbnail,
1488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ThumbnailScore& score) {
1489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get() || !thumbnail_db_.get())
1490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLRow url_row;
1493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLID url_id = db_->GetRowForURL(url, &url_row);
1494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url_id) {
1495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail_db_->SetPageThumbnail(url, url_id, thumbnail, score,
1496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    url_row.last_visit());
1497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommit();
1500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::GetPageThumbnail(
1503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<GetPageThumbnailRequest> request,
1504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& page_url) {
1505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<RefCountedBytes> data;
1509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetPageThumbnailDirectly(page_url, &data);
1510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(GetPageThumbnailRequest::TupleType(
1512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->handle(), data));
1513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::GetPageThumbnailDirectly(
1516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& page_url,
1517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<RefCountedBytes>* data) {
1518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (thumbnail_db_.get()) {
1519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *data = new RefCountedBytes;
1520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Time the result.
1522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TimeTicks beginning_time = TimeTicks::Now();
1523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::RedirectList redirects;
1525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLID url_id;
1526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool success = false;
1527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If there are some redirects, try to get a thumbnail from the last
1529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // redirect destination.
1530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (GetMostRecentRedirectsFrom(page_url, &redirects) &&
1531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !redirects.empty()) {
1532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if ((url_id = db_->GetRowForURL(redirects.back(), NULL)))
1533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        success = thumbnail_db_->GetPageThumbnail(url_id, &(*data)->data);
1534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we don't have a thumbnail from redirects, try the URL directly.
1537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!success) {
1538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if ((url_id = db_->GetRowForURL(page_url, NULL)))
1539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        success = thumbnail_db_->GetPageThumbnail(url_id, &(*data)->data);
1540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // In this rare case, we start to mine the older redirect sessions
1543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // from the visit table to try to find a thumbnail.
1544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!success) {
1545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      success = GetThumbnailFromOlderRedirect(page_url, &(*data)->data);
1546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!success)
1549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *data = NULL;  // This will tell the callback there was an error.
1550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_TIMES("History.GetPageThumbnail",
1552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        TimeTicks::Now() - beginning_time);
1553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1556513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid HistoryBackend::MigrateThumbnailsDatabase() {
1557513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // If there is no History DB, we can't record that the migration was done.
1558513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // It will be recorded on the next run.
1559513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (db_.get()) {
1560513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // If there is no thumbnail DB, we can still record a successful migration.
1561513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (thumbnail_db_.get()) {
1562513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
1563513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                             GetFaviconsFileName());
1564513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
1565513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    db_->ThumbnailMigrationDone();
1566513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
1567513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
1568513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
1569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::GetThumbnailFromOlderRedirect(
1570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& page_url,
1571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<unsigned char>* data) {
1572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Look at a few previous visit sessions.
1573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitVector older_sessions;
1574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLID page_url_id = db_->GetRowForURL(page_url, NULL);
1575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kVisitsToSearchForThumbnail = 4;
1576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->GetMostRecentVisitsForURL(
1577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      page_url_id, kVisitsToSearchForThumbnail, &older_sessions);
1578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Iterate across all those previous visits, and see if any of the
1580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // final destinations of those redirect chains have a good thumbnail
1581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // for us.
1582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = false;
1583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (VisitVector::const_iterator it = older_sessions.begin();
1584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       !success && it != older_sessions.end(); ++it) {
1585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::RedirectList redirects;
1586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (it->visit_id) {
1587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetRedirectsFromSpecificVisit(it->visit_id, &redirects);
1588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!redirects.empty()) {
1590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        URLID url_id;
1591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if ((url_id = db_->GetRowForURL(redirects.back(), NULL)))
1592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          success = thumbnail_db_->GetPageThumbnail(url_id, data);
1593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return success;
1598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1600ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid HistoryBackend::GetFavicon(scoped_refptr<GetFaviconRequest> request,
1601ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                const GURL& icon_url,
1602ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                int icon_types) {
1603ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UpdateFaviconMappingAndFetchImpl(NULL, icon_url, request, icon_types);
1604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1606ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid HistoryBackend::UpdateFaviconMappingAndFetch(
1607ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<GetFaviconRequest> request,
1608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& page_url,
1609ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& icon_url,
1610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    IconType icon_type) {
1611ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UpdateFaviconMappingAndFetchImpl(&page_url, icon_url, request, icon_type);
1612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1614ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid HistoryBackend::SetFaviconOutOfDateForPage(const GURL& page_url) {
1615ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<IconMapping> icon_mappings;
1616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1617ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thumbnail_db_.get() ||
1618ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !thumbnail_db_->GetIconMappingsForPageURL(page_url,
1619ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                &icon_mappings))
1620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1622ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
1623ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       m != icon_mappings.end(); ++m) {
1624ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    thumbnail_db_->SetFaviconLastUpdateTime(m->icon_id, Time());
1625ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommit();
1627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::SetImportedFavicons(
1630ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<ImportedFaviconUsage>& favicon_usage) {
1631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get() || !thumbnail_db_.get())
1632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time now = Time::Now();
1635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Track all URLs that had their favicons set or updated.
1637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<GURL> favicons_changed;
1638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < favicon_usage.size(); i++) {
1640ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL(
1641ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        favicon_usage[i].favicon_url, history::FAVICON, NULL);
1642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!favicon_id) {
1643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This favicon doesn't exist yet, so we create it using the given data.
1644ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicon_id = thumbnail_db_->AddFavicon(favicon_usage[i].favicon_url,
1645ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                             history::FAVICON);
1646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!favicon_id)
1647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;  // Unable to add the favicon.
1648ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      thumbnail_db_->SetFavicon(favicon_id,
1649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          new RefCountedBytes(favicon_usage[i].png_data), now);
1650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Save the mapping from all the URLs to the favicon.
1653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BookmarkService* bookmark_service = GetBookmarkService();
1654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
1655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         url != favicon_usage[i].urls.end(); ++url) {
1656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLRow url_row;
1657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!db_->GetRowForURL(*url, &url_row)) {
1658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // If the URL is present as a bookmark, add the url in history to
1659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // save the favicon mapping. This will match with what history db does
1660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // for regular bookmarked URLs with favicons - when history db is
1661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // cleaned, we keep an entry in the db with 0 visits as long as that
1662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // url is bookmarked.
1663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (bookmark_service && bookmark_service_->IsBookmarked(*url)) {
1664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          URLRow url_info(*url);
1665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          url_info.set_visit_count(0);
1666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          url_info.set_typed_count(0);
1667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          url_info.set_last_visit(base::Time());
1668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          url_info.set_hidden(false);
1669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          db_->AddURL(url_info);
1670ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          thumbnail_db_->AddIconMapping(*url, favicon_id);
1671ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          favicons_changed.insert(*url);
1672ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
1673ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
1674ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (!thumbnail_db_->GetIconMappingForPageURL(*url, FAVICON, NULL)) {
1675ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          // URL is present in history, update the favicon *only* if it is not
1676ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          // set already.
1677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          thumbnail_db_->AddIconMapping(*url, favicon_id);
1678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          favicons_changed.insert(*url);
1679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
1680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!favicons_changed.empty()) {
1685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Send the notification about the changed favicon URLs.
1686ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FaviconChangeDetails* changed_details = new FaviconChangeDetails;
1687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    changed_details->urls.swap(favicons_changed);
1688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BroadcastNotifications(NotificationType::FAVICON_CHANGED, changed_details);
1689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1692ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid HistoryBackend::UpdateFaviconMappingAndFetchImpl(
1693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL* page_url,
1694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& icon_url,
1695ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<GetFaviconRequest> request,
1696ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int icon_types) {
1697ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Check only a single type was given when the page_url was specified.
1698ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!page_url || (page_url && (icon_types == FAVICON ||
1699ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      icon_types == TOUCH_ICON || icon_types == TOUCH_PRECOMPOSED_ICON)));
1700ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1704ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FaviconData favicon;
1705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (thumbnail_db_.get()) {
1707ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const FaviconID favicon_id =
1708ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        thumbnail_db_->GetFaviconIDForFaviconURL(
1709ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            icon_url, icon_types, &favicon.icon_type);
1710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (favicon_id) {
1711ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
1712ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicon.known_icon = true;
1713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Time last_updated;
1714ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (thumbnail_db_->GetFavicon(favicon_id, &last_updated, &data->data,
1715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    NULL)) {
1716ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        favicon.expired = (Time::Now() - last_updated) >
1717ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            TimeDelta::FromDays(kFaviconRefetchDays);
1718ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        favicon.image_data = data;
1719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (page_url)
1722ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        SetFaviconMapping(*page_url, favicon_id, favicon.icon_type);
1723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // else case, haven't cached entry yet. Caller is responsible for
1725ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // downloading the favicon and invoking SetFavicon.
1726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1727ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  request->ForwardResult(GetFaviconRequest::TupleType(
1728ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             request->handle(), favicon));
1729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1731ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid HistoryBackend::GetFaviconForURL(
1732ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<GetFaviconRequest> request,
1733ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& page_url,
1734ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int icon_types) {
1735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1738ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FaviconData favicon;
1739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get() && thumbnail_db_.get()) {
1741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Time the query.
1742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TimeTicks beginning_time = TimeTicks::Now();
1743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1744ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::vector<IconMapping> icon_mappings;
1745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time last_updated;
1746ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
1747ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) &&
1748ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (icon_mappings.front().icon_type & icon_types) &&
1749ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        thumbnail_db_->GetFavicon(icon_mappings.front().icon_id, &last_updated,
1750ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                  &data->data, &favicon.icon_url)) {
1751ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicon.known_icon = true;
1752ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicon.expired = (Time::Now() - last_updated) >
1753ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          TimeDelta::FromDays(kFaviconRefetchDays);
1754ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicon.icon_type = icon_mappings.front().icon_type;
1755ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicon.image_data = data;
1756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1758ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    UMA_HISTOGRAM_TIMES("History.GetFavIconForURL",  // historical name
1759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        TimeTicks::Now() - beginning_time);
1760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(
1763ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetFaviconRequest::TupleType(request->handle(), favicon));
1764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1766ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid HistoryBackend::SetFavicon(
1767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& page_url,
1768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& icon_url,
1769ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<RefCountedMemory> data,
1770ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    IconType icon_type) {
1771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(data.get());
1772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!thumbnail_db_.get() || !db_.get())
1773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1775ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FaviconID id = thumbnail_db_->GetFaviconIDForFaviconURL(
1776ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      icon_url, icon_type, NULL);
1777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!id)
1778ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    id = thumbnail_db_->AddFavicon(icon_url, icon_type);
1779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set the image data.
1781ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thumbnail_db_->SetFavicon(id, data, Time::Now());
1782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1783ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetFaviconMapping(page_url, id, icon_type);
1784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1786ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid HistoryBackend::SetFaviconMapping(const GURL& page_url,
1787ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       FaviconID id,
1788ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       IconType icon_type) {
1789ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thumbnail_db_.get())
1790ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
1791ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find all the pages whose favicons we should set, we want to set it for
1793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // all the pages in the redirect chain if it redirected.
1794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history::RedirectList dummy_list;
1795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history::RedirectList* redirects;
1796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RedirectCache::iterator iter = recent_redirects_.Get(page_url);
1797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (iter != recent_redirects_.end()) {
1798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    redirects = &iter->second;
1799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This redirect chain should have the destination URL as the last item.
1801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(!redirects->empty());
1802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(redirects->back() == page_url);
1803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No redirect chain stored, make up one containing the URL we want to we
1805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // can use the same logic below.
1806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dummy_list.push_back(page_url);
1807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    redirects = &dummy_list;
1808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<GURL> favicons_changed;
1811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Save page <-> favicon association.
1813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (history::RedirectList::const_iterator i(redirects->begin());
1814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != redirects->end(); ++i) {
1815ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FaviconID replaced_id;
1816ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (AddOrUpdateIconMapping(*i, id, icon_type, &replaced_id)) {
1817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The page's favicon ID changed. This means that the one we just
1818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // changed from could have been orphaned, and we need to re-check it.
1819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This is not super fast, but this case will get triggered rarely,
1820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // since normally a page will always map to the same favicon ID. It
1821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // will mostly happen for favicons we import.
1822ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (replaced_id && !thumbnail_db_->HasMappingFor(replaced_id))
1823ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        thumbnail_db_->DeleteFavicon(replaced_id);
1824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1825ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicons_changed.insert(*i);
1826ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send the notification about the changed favicons.
1830ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FaviconChangeDetails* changed_details = new FaviconChangeDetails;
1831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  changed_details->urls.swap(favicons_changed);
1832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BroadcastNotifications(NotificationType::FAVICON_CHANGED, changed_details);
1833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommit();
1835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1837ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool HistoryBackend::AddOrUpdateIconMapping(const GURL& page_url,
1838ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            FaviconID id,
1839ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            IconType icon_type,
1840ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            FaviconID* replaced_icon) {
1841ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *replaced_icon = 0;
1842ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<IconMapping> icon_mappings;
1843ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings)) {
1844ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // There is no mapping add it directly.
1845ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    thumbnail_db_->AddIconMapping(page_url, id);
1846ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
1847ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1848ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Iterate all matched icon mappings,
1849ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // a. If the given icon id and matched icon id are same, return.
1850ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // b. If the given icon type and matched icon type are same, but icon id
1851ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //    are not, update the IconMapping.
1852ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // c. If the given icon_type and matched icon type are not same, but
1853ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //    either of them is ICON_TOUCH or ICON_PRECOMPOSED_TOUCH, update the
1854ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //    IconMapping.
1855ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // d. Otherwise add a icon mapping.
1856ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
1857ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       m != icon_mappings.end(); ++m) {
1858ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (m->icon_id == id)
1859ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // The mapping is already there.
1860ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
1861ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1862ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if ((icon_type == TOUCH_ICON && m->icon_type == TOUCH_PRECOMPOSED_ICON) ||
1863ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (icon_type == TOUCH_PRECOMPOSED_ICON && m->icon_type == TOUCH_ICON) ||
1864ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (icon_type == m->icon_type)) {
1865ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      thumbnail_db_->UpdateIconMapping(m->mapping_id, id);
1866ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *replaced_icon = m->icon_id;
1867ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return true;
1868ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1869ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1870ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thumbnail_db_->AddIconMapping(page_url, id);
1871ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
1872ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1873ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::Commit() {
1875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
1876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Note that a commit may not actually have been scheduled if a caller
1879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // explicitly calls this instead of using ScheduleCommit. Likewise, we
1880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // may reset the flag written by a pending commit. But this is OK! It
1881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will merely cause extra commits (which is kind of the idea). We
1882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // could optimize more for this case (we may get two extra commits in
1883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // some cases) but it hasn't been important yet.
1884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CancelScheduledCommit();
1885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->CommitTransaction();
1887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
1888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->BeginTransaction();
1889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (thumbnail_db_.get()) {
1891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail_db_->CommitTransaction();
1892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
1893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "Somebody left a transaction open";
1894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail_db_->BeginTransaction();
1895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (archived_db_.get()) {
1898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_->CommitTransaction();
1899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_->BeginTransaction();
1900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_database_.get()) {
1903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->CommitTransaction();
1904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->BeginTransaction();
1905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::ScheduleCommit() {
1909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (scheduled_commit_.get())
1910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scheduled_commit_ = new CommitLaterTask(this);
1912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostDelayedTask(FROM_HERE,
1913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(scheduled_commit_.get(),
1914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        &CommitLaterTask::RunCommit),
1915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kCommitIntervalMs);
1916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::CancelScheduledCommit() {
1919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (scheduled_commit_) {
1920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scheduled_commit_->Cancel();
1921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scheduled_commit_ = NULL;
1922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::ProcessDBTaskImpl() {
1926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get()) {
1927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // db went away, release all the refs.
1928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ReleaseDBTasks();
1929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove any canceled tasks.
1933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
1934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_task_requests_.front()->Release();
1935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_task_requests_.pop_front();
1936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_task_requests_.empty())
1938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Run the first task.
1941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HistoryDBTaskRequest* request = db_task_requests_.front();
1942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_task_requests_.pop_front();
1943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->value->RunOnDBThread(this, db_.get())) {
1944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The task is done. Notify the callback.
1945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->ForwardResult(HistoryDBTaskRequest::TupleType());
1946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We AddRef'd the request before adding, need to release it now.
1947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->Release();
1948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Tasks wants to run some more. Schedule it at the end of current tasks.
1950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_task_requests_.push_back(request);
1951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // And process it after an invoke later.
1952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
1953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        this, &HistoryBackend::ProcessDBTaskImpl));
1954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::ReleaseDBTasks() {
1958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::list<HistoryDBTaskRequest*>::iterator i =
1959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
1960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->Release();
1961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_task_requests_.clear();
1963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
1966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
1967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Generic operations
1968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
1969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
1970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
1972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<GURL>::const_iterator url = urls.begin(); url != urls.end();
1973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++url) {
1974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    expirer_.DeleteURL(*url);
1975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->GetStartDate(&first_recorded_time_);
1978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Force a commit, if the user is deleting something for privacy reasons, we
1979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // want to get it on disk ASAP.
1980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Commit();
1981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::DeleteURL(const GURL& url) {
1984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  expirer_.DeleteURL(url);
1985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->GetStartDate(&first_recorded_time_);
1987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Force a commit, if the user is deleting something for privacy reasons, we
1988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // want to get it on disk ASAP.
1989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Commit();
1990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::ExpireHistoryBetween(
1993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<ExpireHistoryRequest> request,
1994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::set<GURL>& restrict_urls,
1995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time begin_time,
1996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time end_time) {
1997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
1998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_.get()) {
2001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (begin_time.is_null() && end_time.is_null() && restrict_urls.empty()) {
2002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Special case deleting all history so it can be faster and to reduce the
2003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // possibility of an information leak.
2004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DeleteAllHistory();
2005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
2006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Clearing parts of history, have the expirer do the depend
2007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
2008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Force a commit, if the user is deleting something for privacy reasons,
2010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // we want to get it on disk ASAP.
2011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Commit();
2012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (begin_time <= first_recorded_time_)
2016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->GetStartDate(&first_recorded_time_);
2017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->ForwardResult(ExpireHistoryRequest::TupleType());
2019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (history_publisher_.get() && restrict_urls.empty())
2021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history_publisher_->DeleteUserHistoryBetween(begin_time, end_time);
2022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_.get())
2026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
2029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLRow url_row;
2030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!db_->GetRowForURL(*i, &url_row))
2031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;  // The URL isn't in the db; nothing to do.
2032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitVector visits;
2034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db_->GetVisitsForURL(url_row.id(), &visits);
2035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (visits.empty())
2037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
2038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::ProcessDBTask(
2042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<HistoryDBTaskRequest> request) {
2043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(request.get());
2044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
2045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool task_scheduled = !db_task_requests_.empty();
2048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure we up the refcount of the request. ProcessDBTaskImpl will
2049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // release when done with the task.
2050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->AddRef();
2051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_task_requests_.push_back(request.get());
2052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!task_scheduled) {
2053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No other tasks are scheduled. Process request now.
2054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProcessDBTaskImpl();
2055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::BroadcastNotifications(
2059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotificationType type,
2060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HistoryDetails* details_deleted) {
2061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(delegate_.get());
2062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_->BroadcastNotifications(type, details_deleted);
2063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Deleting --------------------------------------------------------------------
2066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HistoryBackend::DeleteAllHistory() {
2068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Our approach to deleting all history is:
2069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //  1. Copy the bookmarks and their dependencies to new tables with temporary
2070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //     names.
2071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //  2. Delete the original tables. Since tables can not share pages, we know
2072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //     that any data we don't want to keep is now in an unused page.
2073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //  3. Renaming the temporary tables to match the original.
2074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //  4. Vacuuming the database to delete the unused pages.
2075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
2076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Since we are likely to have very few bookmarks and their dependencies
2077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // compared to all history, this is also much faster than just deleting from
2078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the original tables directly.
2079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get the bookmarked URLs.
2081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<GURL> starred_urls;
2082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkService* bookmark_service = GetBookmarkService();
2083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (bookmark_service)
2084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bookmark_service_->GetBookmarks(&starred_urls);
2085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<URLRow> kept_urls;
2087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < starred_urls.size(); i++) {
2088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLRow row;
2089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!db_->GetRowForURL(starred_urls[i], &row))
2090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
2091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Clear the last visit time so when we write these rows they are "clean."
2093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    row.set_last_visit(Time());
2094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    row.set_visit_count(0);
2095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    row.set_typed_count(0);
2096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    kept_urls.push_back(row);
2097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Clear thumbnail and favicon history. The favicons for the given URLs will
2100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // be kept.
2101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ClearAllThumbnailHistory(&kept_urls)) {
2102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Thumbnail history could not be cleared";
2103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We continue in this error case. If the user wants to delete their
2104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // history, we should delete as much as we can.
2105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore,
2108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we clear the list afterwards to make sure nobody uses this invalid data.
2109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ClearAllMainHistory(kept_urls))
2110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Main history could not be cleared";
2111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  kept_urls.clear();
2112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Delete FTS files & archived history.
2114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_database_.get()) {
2115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We assume that the text database has one transaction on them that we need
2116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // to close & restart (the long-running history transaction).
2117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->CommitTransaction();
2118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->DeleteAll();
2119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_database_->BeginTransaction();
2120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (archived_db_.get()) {
2123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Close the database and delete the file.
2124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_.reset();
2125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath archived_file_name = GetArchivedFileName();
2126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    file_util::Delete(archived_file_name, false);
2127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Now re-initialize the database (which may fail).
2129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_.reset(new ArchivedDatabase());
2130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!archived_db_->Init(archived_file_name)) {
2131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(WARNING) << "Could not initialize the archived database.";
2132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      archived_db_.reset();
2133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
2134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Open our long-running transaction on this database.
2135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      archived_db_->BeginTransaction();
2136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->GetStartDate(&first_recorded_time_);
2140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send out the notfication that history is cleared. The in-memory datdabase
2142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will pick this up and clear itself.
2143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLsDeletedDetails* details = new URLsDeletedDetails;
2144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  details->all_history = true;
2145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BroadcastNotifications(NotificationType::HISTORY_URLS_DELETED, details);
2146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::ClearAllThumbnailHistory(
2149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<URLRow>* kept_urls) {
2150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!thumbnail_db_.get()) {
2151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // When we have no reference to the thumbnail database, maybe there was an
2152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // error opening it. In this case, we just try to blow it away to try to
2153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // fix the error if it exists. This may fail, in which case either the
2154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // file doesn't exist or there's no more we can do.
2155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    file_util::Delete(GetThumbnailFileName(), false);
2156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
2157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create the duplicate favicon table, this is where the favicons we want
2160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to keep will be stored.
2161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thumbnail_db_->InitTemporaryFaviconsTable())
2162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
2163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thumbnail_db_->InitTemporaryIconMappingTable())
2165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
2166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This maps existing favicon IDs to the ones in the temporary table.
2168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  typedef std::map<FaviconID, FaviconID> FaviconMap;
2169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FaviconMap copied_favicons;
2170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy all unique favicons to the temporary table, and update all the
2172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // URLs to have the new IDs.
2173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<URLRow>::iterator i = kept_urls->begin();
2174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != kept_urls->end(); ++i) {
2175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::vector<IconMapping> icon_mappings;
2176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!thumbnail_db_->GetIconMappingsForPageURL(i->url(), &icon_mappings))
2177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
2178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
2180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         m != icon_mappings.end(); ++m) {
2181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FaviconID old_id = m->icon_id;
2182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FaviconID new_id;
2183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FaviconMap::const_iterator found = copied_favicons.find(old_id);
2184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (found == copied_favicons.end()) {
2185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        new_id = thumbnail_db_->CopyToTemporaryFaviconTable(old_id);
2186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        copied_favicons[old_id] = new_id;
2187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
2188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // We already encountered a URL that used this favicon, use the ID we
2189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // previously got.
2190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        new_id = found->second;
2191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
2192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Add Icon mapping, and we don't care wheteher it suceeded or not.
2193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      thumbnail_db_->AddToTemporaryIconMappingTable(i->url(), new_id);
2194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Rename the duplicate favicon and icon_mapping back table and recreate the
2198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // other tables. This will make the database consistent again.
2199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thumbnail_db_->CommitTemporaryFaviconTable();
2200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thumbnail_db_->CommitTemporaryIconMappingTable();
2201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail_db_->RecreateThumbnailTable();
2203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Vacuum to remove all the pages associated with the dropped tables. There
2205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // must be no transaction open on the table when we do this. We assume that
2206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // our long-running transaction is open, so we complete it and start it again.
2207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(thumbnail_db_->transaction_nesting() == 1);
2208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail_db_->CommitTransaction();
2209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail_db_->Vacuum();
2210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail_db_->BeginTransaction();
2211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
2212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HistoryBackend::ClearAllMainHistory(
2215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<URLRow>& kept_urls) {
2216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create the duplicate URL table. We will copy the kept URLs into this.
2217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_->CreateTemporaryURLTable())
2218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
2219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Insert the URLs into the temporary table, we need to keep a map of changed
2221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // IDs since the ID will be different in the new table.
2222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typedef std::map<URLID, URLID> URLIDMap;
2223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLIDMap old_to_new;  // Maps original ID to new one.
2224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<URLRow>::const_iterator i = kept_urls.begin();
2225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != kept_urls.end();
2226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++i) {
2227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLID new_id = db_->AddTemporaryURL(*i);
2228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    old_to_new[i->id()] = new_id;
2229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Replace the original URL table with the temporary one.
2232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!db_->CommitTemporaryURLTable())
2233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
2234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Delete the old tables and recreate them empty.
2236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->RecreateAllTablesButURL();
2237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Vacuum to reclaim the space from the dropped tables. This must be done
2239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // when there is no transaction open, and we assume that our long-running
2240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // transaction is currently open.
2241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->CommitTransaction();
2242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->Vacuum();
2243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->BeginTransaction();
2244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_->GetStartDate(&first_recorded_time_);
2245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
2247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2249c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkService* HistoryBackend::GetBookmarkService() {
2250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (bookmark_service_)
2251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bookmark_service_->BlockTillLoaded();
2252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return bookmark_service_;
2253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace history
2256