1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian 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/expire_history_backend.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <limits>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/compiler_specific.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_service.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/archived_database.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_database.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_notifications.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/text_database.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/text_database_manager.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/thumbnail_database.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of days by which the expiration threshold is advanced for items
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// that we want to expire early, such as those of AUTO_SUBFRAME transition type.
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kEarlyExpirationAdvanceDays = 30;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Reads all types of visits starting from beginning of time to the given end
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// time. This is the most general reader.
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass AllVisitsReader : public ExpiringVisitsReader {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual bool Read(Time end_time, HistoryDatabase* db,
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    VisitVector* visits, int max_visits) const {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(db) << "must have a database to operate upon";
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(visits) << "visit vector has to exist in order to populate it";
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db->GetAllVisitsInRange(Time(), end_time, max_visits, visits);
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // When we got the maximum number of visits we asked for, we say there could
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // be additional things to expire now.
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return static_cast<int>(visits->size()) == max_visits;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Reads only AUTO_SUBFRAME visits, within a computed range. The range is
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// computed as follows:
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// * |begin_time| is read from the meta table. This value is updated whenever
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   there are no more additional visits to expire by this reader.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// * |end_time| is advanced forward by a constant (kEarlyExpirationAdvanceDay),
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   but not past the current time.
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass AutoSubframeVisitsReader : public ExpiringVisitsReader {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual bool Read(Time end_time, HistoryDatabase* db,
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    VisitVector* visits, int max_visits) const {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(db) << "must have a database to operate upon";
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(visits) << "visit vector has to exist in order to populate it";
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time begin_time = db->GetEarlyExpirationThreshold();
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Advance |end_time| to expire early.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time early_end_time = end_time +
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TimeDelta::FromDays(kEarlyExpirationAdvanceDays);
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We don't want to set the early expiration threshold to a time in the
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // future.
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time now = Time::Now();
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (early_end_time > now)
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      early_end_time = now;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    db->GetVisitsInRangeForTransition(begin_time, early_end_time,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      max_visits,
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      PageTransition::AUTO_SUBFRAME,
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      visits);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool more = static_cast<int>(visits->size()) == max_visits;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!more)
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db->UpdateEarlyExpirationThreshold(early_end_time);
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return more;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if this visit is worth archiving. Otherwise, this visit is not
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// worth saving (for example, subframe navigations and redirects) and we can
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// just delete it when it gets old.
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ShouldArchiveVisit(const VisitRow& visit) {
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int no_qualifier = PageTransition::StripQualifier(visit.transition);
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // These types of transitions are always "important" and the user will want
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to see them.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (no_qualifier == PageTransition::TYPED ||
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      no_qualifier == PageTransition::AUTO_BOOKMARK ||
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      no_qualifier == PageTransition::START_PAGE)
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only archive these "less important" transitions when they were the final
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // navigation and not part of a redirect chain.
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((no_qualifier == PageTransition::LINK ||
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       no_qualifier == PageTransition::FORM_SUBMIT ||
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       no_qualifier == PageTransition::KEYWORD ||
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       no_qualifier == PageTransition::GENERATED) &&
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      visit.transition & PageTransition::CHAIN_END)
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The transition types we ignore are AUTO_SUBFRAME and MANUAL_SUBFRAME.
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of visits we will expire very time we check for old items. This
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Prevents us from doing too much work any given time.
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kNumExpirePerIteration = 10;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of seconds between checking for items that should be expired when
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we think there might be more items to expire. This timeout is used when the
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// last expiration found at least kNumExpirePerIteration and we want to check
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// again "soon."
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kExpirationDelaySec = 30;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of minutes between checking, as with kExpirationDelaySec, but
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// when we didn't find enough things to expire last time. If there was no
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// history to expire last iteration, it's likely there is nothing next
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// iteration, so we want to wait longer before checking to avoid wasting CPU.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kExpirationEmptyDelayMin = 5;
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of minutes that we wait for before scheduling a task to
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// delete old history index files.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kIndexExpirationDelayMin = 2;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of the most recent months for which we do not want to delete
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the history index files.
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kStoreHistoryIndexesForMonths = 12;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct ExpireHistoryBackend::DeleteDependencies {
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The time range affected. These can be is_null() to be unbounded in one
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // or both directions.
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::Time begin_time, end_time;
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ----- Filled by DeleteVisitRelatedInfo or manually if a function doesn't
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //       call that function. -----
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The unique URL rows affected by this delete.
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<URLID, URLRow> affected_urls;
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ----- Filled by DeleteOneURL -----
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The URLs deleted during this operation.
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<URLRow> deleted_urls;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The list of all favicon IDs that the affected URLs had. Favicons will be
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // shared between all URLs with the same favicon, so this is the set of IDs
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that we will need to check when the delete operations are complete.
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::set<FaviconID> affected_favicons;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Tracks the set of databases that have changed so we can optimize when
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // when we're done.
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TextDatabaseManager::ChangeSet text_db_changes;
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExpireHistoryBackend::ExpireHistoryBackend(
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BroadcastNotificationDelegate* delegate,
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BookmarkService* bookmark_service)
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : delegate_(delegate),
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      main_db_(NULL),
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      archived_db_(NULL),
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      thumb_db_(NULL),
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      text_db_(NULL),
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)),
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bookmark_service_(bookmark_service) {
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExpireHistoryBackend::~ExpireHistoryBackend() {
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::SetDatabases(HistoryDatabase* main_db,
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        ArchivedDatabase* archived_db,
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        ThumbnailDatabase* thumb_db,
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        TextDatabaseManager* text_db) {
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  main_db_ = main_db;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  archived_db_ = archived_db;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumb_db_ = thumb_db;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text_db_ = text_db;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::DeleteURL(const GURL& url) {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!main_db_)
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLRow url_row;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!main_db_->GetRowForURL(url, &url_row))
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;  // Nothing to delete.
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Collect all the visits and delete them. Note that we don't give up if
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // there are no visits, since the URL could still have an entry that we should
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // delete.
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(brettw): bug 1171148: We should also delete from the archived DB.
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitVector visits;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  main_db_->GetVisitsForURL(url_row.id(), &visits);
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteDependencies dependencies;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteVisitRelatedInfo(visits, &dependencies);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We skip ExpireURLsForVisits (since we are deleting from the URL, and not
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // starting with visits in a given time range). We therefore need to call the
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // deletion and favicon update functions manually.
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkService* bookmark_service = GetBookmarkService();
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool is_bookmarked =
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (bookmark_service && bookmark_service->IsBookmarked(url));
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteOneURL(url_row, is_bookmarked, &dependencies);
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!is_bookmarked)
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DeleteFaviconsIfPossible(dependencies.affected_favicons);
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_db_)
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_db_->OptimizeChangedDatabases(dependencies.text_db_changes);
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BroadcastDeleteNotifications(&dependencies);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::ExpireHistoryBetween(
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::set<GURL>& restrict_urls, Time begin_time, Time end_time) {
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!main_db_)
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // There may be stuff in the text database manager's temporary cache.
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_db_)
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_db_->DeleteFromUncommitted(restrict_urls, begin_time, end_time);
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find the affected visits and delete them.
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(brettw): bug 1171164: We should query the archived database here, too.
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitVector visits;
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  main_db_->GetAllVisitsInRange(begin_time, end_time, 0, &visits);
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!restrict_urls.empty()) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<URLID> url_ids;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::set<GURL>::const_iterator url = restrict_urls.begin();
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        url != restrict_urls.end(); ++url)
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_ids.insert(main_db_->GetRowForURL(*url, NULL));
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitVector all_visits;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    all_visits.swap(visits);
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (VisitVector::iterator visit = all_visits.begin();
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         visit != all_visits.end(); ++visit) {
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (url_ids.find(visit->url_id) != url_ids.end())
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        visits.push_back(*visit);
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (visits.empty())
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteDependencies dependencies;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteVisitRelatedInfo(visits, &dependencies);
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Delete or update the URLs affected. We want to update the visit counts
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // since this is called by the user who wants to delete their recent history,
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and we don't want to leave any evidence.
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExpireURLsForVisits(visits, &dependencies);
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteFaviconsIfPossible(dependencies.affected_favicons);
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // An is_null begin time means that all history should be deleted.
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BroadcastDeleteNotifications(&dependencies);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Pick up any bits possibly left over.
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ParanoidExpireHistory();
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::ArchiveHistoryBefore(Time end_time) {
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!main_db_)
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Archive as much history as possible before the given date.
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ArchiveSomeOldHistory(end_time, GetAllVisitsReader(),
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        std::numeric_limits<size_t>::max());
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ParanoidExpireHistory();
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::InitWorkQueue() {
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(work_queue_.empty()) << "queue has to be empty prior to init";
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < readers_.size(); i++)
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    work_queue_.push(readers_[i]);
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst ExpiringVisitsReader* ExpireHistoryBackend::GetAllVisitsReader() {
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!all_visits_reader_.get())
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    all_visits_reader_.reset(new AllVisitsReader());
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return all_visits_reader_.get();
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst ExpiringVisitsReader*
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExpireHistoryBackend::GetAutoSubframeVisitsReader() {
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!auto_subframe_visits_reader_.get())
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    auto_subframe_visits_reader_.reset(new AutoSubframeVisitsReader());
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return auto_subframe_visits_reader_.get();
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::StartArchivingOldStuff(
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TimeDelta expiration_threshold) {
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  expiration_threshold_ = expiration_threshold;
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove all readers, just in case this was method was called before.
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  readers_.clear();
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For now, we explicitly add all known readers. If we come up with more
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // reader types (in case we want to expire different types of visits in
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // different ways), we can make it be populated by creator/owner of
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ExpireHistoryBackend.
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  readers_.push_back(GetAllVisitsReader());
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  readers_.push_back(GetAutoSubframeVisitsReader());
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Initialize the queue with all tasks for the first set of iterations.
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InitWorkQueue();
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleArchive();
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleExpireHistoryIndexFiles();
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::DeleteFaviconsIfPossible(
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::set<FaviconID>& favicon_set) {
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thumb_db_)
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::set<FaviconID>::const_iterator i = favicon_set.begin();
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != favicon_set.end(); ++i) {
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!thumb_db_->HasMappingFor(*i))
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      thumb_db_->DeleteFavicon(*i);
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::BroadcastDeleteNotifications(
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DeleteDependencies* dependencies) {
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!dependencies->deleted_urls.empty()) {
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Broadcast the URL deleted notification. Note that we also broadcast when
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we were requested to delete everything even if that was a NOP, since
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // some components care to know when history is deleted (it's up to them to
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // determine if they care whether anything was deleted).
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLsDeletedDetails* deleted_details = new URLsDeletedDetails;
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    deleted_details->all_history = false;
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<URLRow> typed_urls_changed;  // Collect this for later.
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < dependencies->deleted_urls.size(); i++) {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      deleted_details->urls.insert(dependencies->deleted_urls[i].url());
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (dependencies->deleted_urls[i].typed_count() > 0)
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        typed_urls_changed.push_back(dependencies->deleted_urls[i]);
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->BroadcastNotifications(NotificationType::HISTORY_URLS_DELETED,
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      deleted_details);
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Broadcast the typed URL changed modification (this updates the inline
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // autocomplete database).
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Note: if we ever need to broadcast changes to more than just typed URLs,
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // this notification should be changed rather than a new "non-typed"
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // notification added. The in-memory database can always do the filtering
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // itself in that case.
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!typed_urls_changed.empty()) {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLsModifiedDetails* modified_details = new URLsModifiedDetails;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      modified_details->changed_urls.swap(typed_urls_changed);
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delegate_->BroadcastNotifications(
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NotificationType::HISTORY_TYPED_URLS_MODIFIED,
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          modified_details);
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::DeleteVisitRelatedInfo(
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const VisitVector& visits,
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DeleteDependencies* dependencies) {
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < visits.size(); i++) {
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete the visit itself.
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    main_db_->DeleteVisit(visits[i]);
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Add the URL row to the affected URL list.
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::map<URLID, URLRow>::const_iterator found =
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        dependencies->affected_urls.find(visits[i].url_id);
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const URLRow* cur_row = NULL;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (found == dependencies->affected_urls.end()) {
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLRow row;
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!main_db_->GetURLRow(visits[i].url_id, &row))
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dependencies->affected_urls[visits[i].url_id] = row;
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cur_row = &dependencies->affected_urls[visits[i].url_id];
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cur_row = &found->second;
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete any associated full-text indexed data.
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (visits[i].is_indexed && text_db_) {
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      text_db_->DeletePageData(visits[i].visit_time, cur_row->url(),
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               &dependencies->text_db_changes);
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::DeleteOneURL(
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const URLRow& url_row,
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool is_bookmarked,
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DeleteDependencies* dependencies) {
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  main_db_->DeleteSegmentForURL(url_row.id());
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The URL may be in the text database manager's temporary cache.
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text_db_) {
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<GURL> restrict_urls;
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    restrict_urls.insert(url_row.url());
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    text_db_->DeleteFromUncommitted(restrict_urls, base::Time(), base::Time());
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!is_bookmarked) {
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dependencies->deleted_urls.push_back(url_row);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete stuff that references this URL.
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (thumb_db_) {
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      thumb_db_->DeleteThumbnail(url_row.id());
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Collect shared information.
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::vector<IconMapping> icon_mappings;
416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) {
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             m != icon_mappings.end(); ++m) {
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          dependencies->affected_favicons.insert(m->icon_id);
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // Delete the mapping entries for the url.
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        thumb_db_->DeleteIconMappings(url_row.url());
423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Last, delete the URL entry.
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    main_db_->DeleteURLRow(url_row.id());
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochURLID ExpireHistoryBackend::ArchiveOneURL(const URLRow& url_row) {
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!archived_db_)
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See if this URL is present in the archived database already. Note that
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we must look up by ID since the URL ID will be different.
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLRow archived_row;
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (archived_db_->GetRowForURL(url_row.url(), &archived_row)) {
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(sky): bug 1168470, need to archive past search terms.
439731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // TODO(brettw): should be copy the visit counts over? This will mean that
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the main DB's visit counts are only for the last 3 months rather than
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // accumulative.
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_row.set_last_visit(url_row.last_visit());
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    archived_db_->UpdateURLRow(archived_row.id(), archived_row);
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return archived_row.id();
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This row is not in the archived DB, add it.
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return archived_db_->AddURL(url_row);
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct ChangedURL {
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ChangedURL() : visit_count(0), typed_count(0) {}
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int visit_count;
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int typed_count;
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::ExpireURLsForVisits(
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const VisitVector& visits,
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DeleteDependencies* dependencies) {
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // First find all unique URLs and the number of visits we're deleting for
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // each one.
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<URLID, ChangedURL> changed_urls;
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < visits.size(); i++) {
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ChangedURL& cur = changed_urls[visits[i].url_id];
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cur.visit_count++;
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // NOTE: This code must stay in sync with HistoryBackend::AddPageVisit().
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // typed, which would eliminate the need for this code.
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PageTransition::Type transition =
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PageTransition::StripQualifier(visits[i].transition);
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((transition == PageTransition::TYPED &&
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         !PageTransition::IsRedirect(visits[i].transition)) ||
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        transition == PageTransition::KEYWORD_GENERATED)
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cur.typed_count++;
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check each unique URL with deleted visits.
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkService* bookmark_service = GetBookmarkService();
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::map<URLID, ChangedURL>::const_iterator i = changed_urls.begin();
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != changed_urls.end(); ++i) {
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The unique URL rows should already be filled into the dependencies.
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLRow& url_row = dependencies->affected_urls[i->first];
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url_row.id())
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;  // URL row doesn't exist in the database.
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Check if there are any other visits for this URL and update the time
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (the time change may not actually be synced to disk below when we're
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // archiving).
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitRow last_visit;
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (main_db_->GetMostRecentVisitForURL(url_row.id(), &last_visit))
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_row.set_last_visit(last_visit.visit_time);
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_row.set_last_visit(Time());
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't delete URLs with visits still in the DB, or bookmarked.
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool is_bookmarked =
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (bookmark_service && bookmark_service->IsBookmarked(url_row.url()));
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!is_bookmarked && url_row.last_visit().is_null()) {
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Not bookmarked and no more visits. Nuke the url.
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DeleteOneURL(url_row, is_bookmarked, dependencies);
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // NOTE: The calls to std::max() below are a backstop, but they should
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // never actually be needed unless the database is corrupt (I think).
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_row.set_visit_count(
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          std::max(0, url_row.visit_count() - i->second.visit_count));
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_row.set_typed_count(
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          std::max(0, url_row.typed_count() - i->second.typed_count));
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Update the db with the new details.
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      main_db_->UpdateURLRow(url_row.id(), url_row);
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::ArchiveURLsAndVisits(
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const VisitVector& visits,
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DeleteDependencies* dependencies) {
5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!archived_db_ || !main_db_)
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure all unique URL rows are added to the dependency list and the
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // archived database. We will also keep the mapping between the main DB URLID
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and the archived one.
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<URLID, URLID> main_id_to_archived_id;
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < visits.size(); i++) {
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::map<URLID, URLRow>::const_iterator found =
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dependencies->affected_urls.find(visits[i].url_id);
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (found == dependencies->affected_urls.end()) {
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Unique URL encountered, archive it.
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLRow row;  // Row in the main DB.
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      URLID archived_id;  // ID in the archived DB.
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!main_db_->GetURLRow(visits[i].url_id, &row) ||
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          !(archived_id = ArchiveOneURL(row))) {
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Failure archiving, skip this one.
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Only add URL to the dependency list once we know we successfully
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // archived it.
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      main_id_to_archived_id[row.id()] = archived_id;
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dependencies->affected_urls[row.id()] = row;
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Retrieve the sources for all the archived visits before archiving.
5503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The returned visit_sources vector should contain the source for each visit
5513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // from visits at the same index.
5523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  VisitSourceMap visit_sources;
5533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  main_db_->GetVisitsSource(visits, &visit_sources);
5543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now archive the visits since we know the URL ID to make them reference.
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The source visit list should still reference the visits in the main DB, but
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we will update it to reflect only the visits that were successfully
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // archived.
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < visits.size(); i++) {
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Construct the visit that we will add to the archived database. We do
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // not store referring visits since we delete many of the visits when
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // archiving.
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VisitRow cur_visit(visits[i]);
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cur_visit.url_id = main_id_to_archived_id[cur_visit.url_id];
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cur_visit.referring_visit = 0;
5663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    VisitSourceMap::iterator iter = visit_sources.find(visits[i].visit_id);
56772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    archived_db_->AddVisit(
56872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        &cur_visit,
5693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        iter == visit_sources.end() ? SOURCE_BROWSED : iter->second);
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Ignore failures, we will delete it from the main DB no matter what.
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::ScheduleArchive() {
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeDelta delay;
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (work_queue_.empty()) {
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If work queue is empty, reset the work queue to contain all tasks and
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // schedule next iteration after a longer delay.
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    InitWorkQueue();
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delay = TimeDelta::FromMinutes(kExpirationEmptyDelayMin);
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delay = TimeDelta::FromSeconds(kExpirationDelaySec);
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostDelayedTask(FROM_HERE, factory_.NewRunnableMethod(
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &ExpireHistoryBackend::DoArchiveIteration), delay.InMilliseconds());
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::DoArchiveIteration() {
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!work_queue_.empty()) << "queue has to be non-empty";
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ExpiringVisitsReader* reader = work_queue_.front();
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool more_to_expire = ArchiveSomeOldHistory(GetCurrentArchiveTime(), reader,
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              kNumExpirePerIteration);
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  work_queue_.pop();
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If there are more items to expire, add the reader back to the queue, thus
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // creating a new task for future iterations.
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (more_to_expire)
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    work_queue_.push(reader);
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleArchive();
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExpireHistoryBackend::ArchiveSomeOldHistory(
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::Time end_time,
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ExpiringVisitsReader* reader,
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int max_visits) {
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!main_db_)
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add an extra time unit to given end time, because
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GetAllVisitsInRange, et al. queries' end value is non-inclusive.
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time effective_end_time =
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Time::FromInternalValue(end_time.ToInternalValue() + 1);
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitVector affected_visits;
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool more_to_expire = reader->Read(effective_end_time, main_db_,
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     &affected_visits, max_visits);
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Some visits we'll delete while others we'll archive.
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VisitVector deleted_visits, archived_visits;
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < affected_visits.size(); i++) {
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ShouldArchiveVisit(affected_visits[i]))
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      archived_visits.push_back(affected_visits[i]);
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      deleted_visits.push_back(affected_visits[i]);
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Do the actual archiving.
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteDependencies archived_dependencies;
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ArchiveURLsAndVisits(archived_visits, &archived_dependencies);
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteVisitRelatedInfo(archived_visits, &archived_dependencies);
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteDependencies deleted_dependencies;
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteVisitRelatedInfo(deleted_visits, &deleted_dependencies);
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This will remove or archive all the affected URLs. Must do the deleting
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // cleanup before archiving so the delete dependencies structure references
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // only those URLs that were actually deleted instead of having some visits
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // archived and then the rest deleted.
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExpireURLsForVisits(deleted_visits, &deleted_dependencies);
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExpireURLsForVisits(archived_visits, &archived_dependencies);
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create a union of all affected favicons (we don't store favicons for
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // archived URLs) and delete them.
647ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::set<FaviconID> affected_favicons(
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      archived_dependencies.affected_favicons);
649ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::set<FaviconID>::const_iterator i =
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           deleted_dependencies.affected_favicons.begin();
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != deleted_dependencies.affected_favicons.end(); ++i) {
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    affected_favicons.insert(*i);
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DeleteFaviconsIfPossible(affected_favicons);
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send notifications for the stuff that was deleted. These won't normally be
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in history views since they were subframes, but they will be in the visited
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // link system, which needs to be updated now. This function is smart enough
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to not do anything if nothing was deleted.
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BroadcastDeleteNotifications(&deleted_dependencies);
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return more_to_expire;
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::ParanoidExpireHistory() {
666731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO(brettw): Bug 1067331: write this to clean up any errors.
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::ScheduleExpireHistoryIndexFiles() {
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!text_db_) {
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Can't expire old history index files because we
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // don't know where they're located.
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeDelta delay = TimeDelta::FromMinutes(kIndexExpirationDelayMin);
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostDelayedTask(
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FROM_HERE, factory_.NewRunnableMethod(
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &ExpireHistoryBackend::DoExpireHistoryIndexFiles),
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delay.InMilliseconds());
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExpireHistoryBackend::DoExpireHistoryIndexFiles() {
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time::Exploded exploded;
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time::Now().LocalExplode(&exploded);
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int cutoff_month =
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      exploded.year * 12 + exploded.month - kStoreHistoryIndexesForMonths;
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TextDatabase::DBIdent cutoff_id =
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (cutoff_month / 12) * 100 + (cutoff_month % 12);
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath::StringType history_index_files_pattern = TextDatabase::file_base();
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history_index_files_pattern.append(FILE_PATH_LITERAL("*"));
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  file_util::FileEnumerator file_enumerator(
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      text_db_->GetDir(), false, file_util::FileEnumerator::FILES,
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_index_files_pattern);
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (FilePath file = file_enumerator.Next(); !file.empty();
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       file = file_enumerator.Next()) {
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TextDatabase::DBIdent file_id = TextDatabase::FileNameToID(file);
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (file_id < cutoff_id)
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      file_util::Delete(file, false);
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkService* ExpireHistoryBackend::GetBookmarkService() {
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We use the bookmark service to determine if a URL is bookmarked. The
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // bookmark service is loaded on a separate thread and may not be done by the
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // time we get here. We therefor block until the bookmarks have finished
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // loading.
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (bookmark_service_)
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bookmark_service_->BlockTillLoaded();
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return bookmark_service_;
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace history
715