summaryrefslogtreecommitdiffstats
path: root/chrome/browser/history/expire_history_backend.h
blob: fdabd77095b98a74d9c88fe51d03113dfb6405eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_
#define CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_

#include <queue>
#include <set>
#include <vector>

#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/history/history_types.h"

class GURL;
class TestingProfile;

namespace history {

class HistoryClient;
class HistoryDatabase;
struct HistoryDetails;
class ThumbnailDatabase;

// Delegate used to broadcast notifications to the main thread.
class BroadcastNotificationDelegate {
 public:
  // Schedules a broadcast of the given notification on the application main
  // thread.
  virtual void BroadcastNotifications(int type,
                                      scoped_ptr<HistoryDetails> details) = 0;

  // Tells typed url sync code to handle URL modifications or deletions.
  virtual void NotifySyncURLsModified(URLRows* rows) = 0;
  virtual void NotifySyncURLsDeleted(bool all_history,
                                     bool expired,
                                     URLRows* rows) = 0;

 protected:
  virtual ~BroadcastNotificationDelegate() {}
};

// Encapsulates visit expiration criteria and type of visits to expire.
class ExpiringVisitsReader {
 public:
  virtual ~ExpiringVisitsReader() {}
  // Populates |visits| from |db|, using provided |end_time| and |max_visits|
  // cap.
  virtual bool Read(base::Time end_time, HistoryDatabase* db,
                    VisitVector* visits, int max_visits) const = 0;
};

typedef std::vector<const ExpiringVisitsReader*> ExpiringVisitsReaders;

// Helper component to HistoryBackend that manages expiration and deleting of
// history.
//
// It will automatically start periodically expiring old history once you call
// StartExpiringOldStuff().
class ExpireHistoryBackend {
 public:
  // The delegate pointer must be non-NULL. We will NOT take ownership of it.
  // HistoryClient may be NULL. The HistoryClient is used when expiring URLS so
  // that we don't remove any URLs or favicons that are bookmarked (visits are
  // removed though).
  ExpireHistoryBackend(BroadcastNotificationDelegate* delegate,
                       HistoryClient* history_client);
  ~ExpireHistoryBackend();

  // Completes initialization by setting the databases that this class will use.
  void SetDatabases(HistoryDatabase* main_db,
                    ThumbnailDatabase* thumb_db);

  // Begins periodic expiration of history older than the given threshold. This
  // will continue until the object is deleted.
  void StartExpiringOldStuff(base::TimeDelta expiration_threshold);

  // Deletes everything associated with a URL.
  void DeleteURL(const GURL& url);

  // Deletes everything associated with each URL in the list.
  void DeleteURLs(const std::vector<GURL>& url);

  // Removes all visits to restrict_urls (or all URLs if empty) in the given
  // time range, updating the URLs accordingly.
  void ExpireHistoryBetween(const std::set<GURL>& restrict_urls,
                            base::Time begin_time, base::Time end_time);

  // Removes all visits to all URLs with the given times, updating the
  // URLs accordingly.  |times| must be in reverse chronological order
  // and not contain any duplicates.
  void ExpireHistoryForTimes(const std::vector<base::Time>& times);

  // Removes the given list of visits, updating the URLs accordingly (similar to
  // ExpireHistoryBetween(), but affecting a specific set of visits).
  void ExpireVisits(const VisitVector& visits);

  // Expires all visits before and including the given time, updating the URLs
  // accordingly. Currently only used for testing.
  void ExpireHistoryBefore(base::Time end_time);

  // Returns the current cut-off time before which we will start expiring stuff.
  // Note that this as an absolute time rather than a delta, so the caller
  // should not save it.
  base::Time GetCurrentExpirationTime() const {
    return base::Time::Now() - expiration_threshold_;
  }

 private:
  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, DeleteFaviconsIfPossible);
  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistory);
  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpiringVisitsReader);
  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistoryWithSource);
  friend class ::TestingProfile;

  struct DeleteEffects {
    DeleteEffects();
    ~DeleteEffects();

    // The time range affected. These can be is_null() to be unbounded in one
    // or both directions.
    base::Time begin_time, end_time;

    // The unique URL rows affected by this delete.
    std::map<URLID, URLRow> affected_urls;

    // The URLs modified, but not deleted, during this operation.
    URLRows modified_urls;

    // The URLs deleted during this operation.
    URLRows deleted_urls;

    // All favicon IDs that the deleted URLs had. Favicons will be shared
    // between all URLs with the same favicon, so this is the set of IDs that we
    // will need to check when the delete operations are complete.
    std::set<favicon_base::FaviconID> affected_favicons;

    // All favicon urls that were actually deleted from the thumbnail db.
    std::set<GURL> deleted_favicons;
  };

  // Deletes the visit-related stuff for all the visits in the given list, and
  // adds the rows for unique URLs affected to the affected_urls list in
  // the dependencies structure.
  void DeleteVisitRelatedInfo(const VisitVector& visits,
                              DeleteEffects* effects);

  // Finds or deletes dependency information for the given URL. Information that
  // is specific to this URL (URL row, thumbnails, etc.) is deleted.
  //
  // This does not affect the visits! This is used for expiration as well as
  // deleting from the UI, and they handle visits differently.
  //
  // Other information will be collected and returned in the output containers.
  // This includes some of the things deleted that are needed elsewhere, plus
  // some things like favicons that could be shared by many URLs, and need to
  // be checked for deletion (this allows us to delete many URLs with only one
  // check for shared information at the end).
  //
  // Assumes the main_db_ is non-NULL.
  //
  // NOTE: If the url is bookmarked only the segments and text db are updated,
  // everything else is unchanged. This is done so that bookmarks retain their
  // favicons and thumbnails.
  void DeleteOneURL(const URLRow& url_row,
                    bool is_bookmarked,
                    DeleteEffects* effects);

  // Deletes all the URLs in the given vector and handles their dependencies.
  // This will delete starred URLs
  void DeleteURLs(const URLRows& urls, DeleteEffects* effects);

  // Expiration involves removing visits, then propagating the visits out from
  // there and delete any orphaned URLs. These will be added to the deleted URLs
  // field of the dependencies and DeleteOneURL will handle deleting out from
  // there. This function does not handle favicons.
  //
  // When a URL is not deleted, the last visit time and the visit and typed
  // counts will be updated.
  //
  // The visits in the given vector should have already been deleted from the
  // database, and the list of affected URLs already be filled into
  // |depenencies->affected_urls|.
  //
  // Starred URLs will not be deleted. The information in the dependencies that
  // DeleteOneURL fills in will be updated, and this function will also delete
  // any now-unused favicons.
  void ExpireURLsForVisits(const VisitVector& visits, DeleteEffects* effects);

  // Deletes the favicons listed in |effects->affected_favicons| if they are
  // unsued. Fails silently (we don't care about favicons so much, so don't want
  // to stop everything if it fails). Fills |expired_favicons| with the set of
  // favicon urls that no longer have associated visits and were therefore
  // expired.
  void DeleteFaviconsIfPossible(DeleteEffects* effects);

  // Enum representing what type of action resulted in the history DB deletion.
  enum DeletionType {
    // User initiated the deletion from the History UI.
    DELETION_USER_INITIATED,
    // History data was automatically expired due to being more than 90 days
    // old.
    DELETION_EXPIRED
  };

  // Broadcasts URL modified and deleted notifications.
  void BroadcastNotifications(DeleteEffects* effects, DeletionType type);

  // Schedules a call to DoExpireIteration.
  void ScheduleExpire();

  // Calls ExpireSomeOldHistory to expire some amount of old history, according
  // to the items in work queue, and schedules another call to happen in the
  // future.
  void DoExpireIteration();

  // Tries to expire the oldest |max_visits| visits from history that are older
  // than |time_threshold|. The return value indicates if we think there might
  // be more history to expire with the current time threshold (it does not
  // indicate success or failure).
  bool ExpireSomeOldHistory(base::Time end_time,
                             const ExpiringVisitsReader* reader,
                             int max_visits);

  // Tries to detect possible bad history or inconsistencies in the database
  // and deletes items. For example, URLs with no visits.
  void ParanoidExpireHistory();

  // Returns the HistoryClient, blocking until the bookmarks are loaded. This
  // may return NULL during testing.
  HistoryClient* GetHistoryClient();

  // Initializes periodic expiration work queue by populating it with with tasks
  // for all known readers.
  void InitWorkQueue();

  // Returns the reader for all visits. This method is only used by the unit
  // tests.
  const ExpiringVisitsReader* GetAllVisitsReader();

  // Returns the reader for AUTO_SUBFRAME visits. This method is only used by
  // the unit tests.
  const ExpiringVisitsReader* GetAutoSubframeVisitsReader();

  // Non-owning pointer to the notification delegate (guaranteed non-NULL).
  BroadcastNotificationDelegate* delegate_;

  // Non-owning pointers to the databases we deal with (MAY BE NULL).
  HistoryDatabase* main_db_;       // Main history database.
  ThumbnailDatabase* thumb_db_;    // Thumbnails and favicons.

  // Used to generate runnable methods to do timers on this class. They will be
  // automatically canceled when this class is deleted.
  base::WeakPtrFactory<ExpireHistoryBackend> weak_factory_;

  // The threshold for "old" history where we will automatically delete it.
  base::TimeDelta expiration_threshold_;

  // List of all distinct types of readers. This list is used to populate the
  // work queue.
  ExpiringVisitsReaders readers_;

  // Work queue for periodic expiration tasks, used by DoExpireIteration() to
  // determine what to do at an iteration, as well as populate it for future
  // iterations.
  std::queue<const ExpiringVisitsReader*> work_queue_;

  // Readers for various types of visits.
  // TODO(dglazkov): If you are adding another one, please consider reorganizing
  // into a map.
  scoped_ptr<ExpiringVisitsReader> all_visits_reader_;
  scoped_ptr<ExpiringVisitsReader> auto_subframe_visits_reader_;

  // The HistoryClient; may be NULL.
  //
  // Use GetHistoryClient to access this, which makes sure the bookmarks are
  // loaded before returning.
  HistoryClient* history_client_;

  DISALLOW_COPY_AND_ASSIGN(ExpireHistoryBackend);
};

}  // namespace history

#endif  // CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_