1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_
6#define CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_
7
8#include <queue>
9#include <set>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/scoped_ptr.h"
15#include "base/memory/weak_ptr.h"
16#include "base/time/time.h"
17#include "chrome/browser/history/history_types.h"
18
19class GURL;
20class TestingProfile;
21
22namespace history {
23
24class HistoryClient;
25class HistoryDatabase;
26struct HistoryDetails;
27class ThumbnailDatabase;
28
29// Delegate used to broadcast notifications to the main thread.
30class BroadcastNotificationDelegate {
31 public:
32  // Schedules a broadcast of the given notification on the application main
33  // thread.
34  virtual void BroadcastNotifications(int type,
35                                      scoped_ptr<HistoryDetails> details) = 0;
36
37  // Tells typed url sync code to handle URL modifications or deletions.
38  virtual void NotifySyncURLsModified(URLRows* rows) = 0;
39  virtual void NotifySyncURLsDeleted(bool all_history,
40                                     bool expired,
41                                     URLRows* rows) = 0;
42
43 protected:
44  virtual ~BroadcastNotificationDelegate() {}
45};
46
47// Encapsulates visit expiration criteria and type of visits to expire.
48class ExpiringVisitsReader {
49 public:
50  virtual ~ExpiringVisitsReader() {}
51  // Populates |visits| from |db|, using provided |end_time| and |max_visits|
52  // cap.
53  virtual bool Read(base::Time end_time, HistoryDatabase* db,
54                    VisitVector* visits, int max_visits) const = 0;
55};
56
57typedef std::vector<const ExpiringVisitsReader*> ExpiringVisitsReaders;
58
59// Helper component to HistoryBackend that manages expiration and deleting of
60// history.
61//
62// It will automatically start periodically expiring old history once you call
63// StartExpiringOldStuff().
64class ExpireHistoryBackend {
65 public:
66  // The delegate pointer must be non-NULL. We will NOT take ownership of it.
67  // HistoryClient may be NULL. The HistoryClient is used when expiring URLS so
68  // that we don't remove any URLs or favicons that are bookmarked (visits are
69  // removed though).
70  ExpireHistoryBackend(BroadcastNotificationDelegate* delegate,
71                       HistoryClient* history_client);
72  ~ExpireHistoryBackend();
73
74  // Completes initialization by setting the databases that this class will use.
75  void SetDatabases(HistoryDatabase* main_db,
76                    ThumbnailDatabase* thumb_db);
77
78  // Begins periodic expiration of history older than the given threshold. This
79  // will continue until the object is deleted.
80  void StartExpiringOldStuff(base::TimeDelta expiration_threshold);
81
82  // Deletes everything associated with a URL.
83  void DeleteURL(const GURL& url);
84
85  // Deletes everything associated with each URL in the list.
86  void DeleteURLs(const std::vector<GURL>& url);
87
88  // Removes all visits to restrict_urls (or all URLs if empty) in the given
89  // time range, updating the URLs accordingly.
90  void ExpireHistoryBetween(const std::set<GURL>& restrict_urls,
91                            base::Time begin_time, base::Time end_time);
92
93  // Removes all visits to all URLs with the given times, updating the
94  // URLs accordingly.  |times| must be in reverse chronological order
95  // and not contain any duplicates.
96  void ExpireHistoryForTimes(const std::vector<base::Time>& times);
97
98  // Removes the given list of visits, updating the URLs accordingly (similar to
99  // ExpireHistoryBetween(), but affecting a specific set of visits).
100  void ExpireVisits(const VisitVector& visits);
101
102  // Expires all visits before and including the given time, updating the URLs
103  // accordingly. Currently only used for testing.
104  void ExpireHistoryBefore(base::Time end_time);
105
106  // Returns the current cut-off time before which we will start expiring stuff.
107  // Note that this as an absolute time rather than a delta, so the caller
108  // should not save it.
109  base::Time GetCurrentExpirationTime() const {
110    return base::Time::Now() - expiration_threshold_;
111  }
112
113 private:
114  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, DeleteFaviconsIfPossible);
115  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistory);
116  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpiringVisitsReader);
117  FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistoryWithSource);
118  friend class ::TestingProfile;
119
120  struct DeleteEffects {
121    DeleteEffects();
122    ~DeleteEffects();
123
124    // The time range affected. These can be is_null() to be unbounded in one
125    // or both directions.
126    base::Time begin_time, end_time;
127
128    // The unique URL rows affected by this delete.
129    std::map<URLID, URLRow> affected_urls;
130
131    // The URLs modified, but not deleted, during this operation.
132    URLRows modified_urls;
133
134    // The URLs deleted during this operation.
135    URLRows deleted_urls;
136
137    // All favicon IDs that the deleted URLs had. Favicons will be shared
138    // between all URLs with the same favicon, so this is the set of IDs that we
139    // will need to check when the delete operations are complete.
140    std::set<favicon_base::FaviconID> affected_favicons;
141
142    // All favicon urls that were actually deleted from the thumbnail db.
143    std::set<GURL> deleted_favicons;
144  };
145
146  // Deletes the visit-related stuff for all the visits in the given list, and
147  // adds the rows for unique URLs affected to the affected_urls list in
148  // the dependencies structure.
149  void DeleteVisitRelatedInfo(const VisitVector& visits,
150                              DeleteEffects* effects);
151
152  // Finds or deletes dependency information for the given URL. Information that
153  // is specific to this URL (URL row, thumbnails, etc.) is deleted.
154  //
155  // This does not affect the visits! This is used for expiration as well as
156  // deleting from the UI, and they handle visits differently.
157  //
158  // Other information will be collected and returned in the output containers.
159  // This includes some of the things deleted that are needed elsewhere, plus
160  // some things like favicons that could be shared by many URLs, and need to
161  // be checked for deletion (this allows us to delete many URLs with only one
162  // check for shared information at the end).
163  //
164  // Assumes the main_db_ is non-NULL.
165  //
166  // NOTE: If the url is bookmarked only the segments and text db are updated,
167  // everything else is unchanged. This is done so that bookmarks retain their
168  // favicons and thumbnails.
169  void DeleteOneURL(const URLRow& url_row,
170                    bool is_bookmarked,
171                    DeleteEffects* effects);
172
173  // Deletes all the URLs in the given vector and handles their dependencies.
174  // This will delete starred URLs
175  void DeleteURLs(const URLRows& urls, DeleteEffects* effects);
176
177  // Expiration involves removing visits, then propagating the visits out from
178  // there and delete any orphaned URLs. These will be added to the deleted URLs
179  // field of the dependencies and DeleteOneURL will handle deleting out from
180  // there. This function does not handle favicons.
181  //
182  // When a URL is not deleted, the last visit time and the visit and typed
183  // counts will be updated.
184  //
185  // The visits in the given vector should have already been deleted from the
186  // database, and the list of affected URLs already be filled into
187  // |depenencies->affected_urls|.
188  //
189  // Starred URLs will not be deleted. The information in the dependencies that
190  // DeleteOneURL fills in will be updated, and this function will also delete
191  // any now-unused favicons.
192  void ExpireURLsForVisits(const VisitVector& visits, DeleteEffects* effects);
193
194  // Deletes the favicons listed in |effects->affected_favicons| if they are
195  // unsued. Fails silently (we don't care about favicons so much, so don't want
196  // to stop everything if it fails). Fills |expired_favicons| with the set of
197  // favicon urls that no longer have associated visits and were therefore
198  // expired.
199  void DeleteFaviconsIfPossible(DeleteEffects* effects);
200
201  // Enum representing what type of action resulted in the history DB deletion.
202  enum DeletionType {
203    // User initiated the deletion from the History UI.
204    DELETION_USER_INITIATED,
205    // History data was automatically expired due to being more than 90 days
206    // old.
207    DELETION_EXPIRED
208  };
209
210  // Broadcasts URL modified and deleted notifications.
211  void BroadcastNotifications(DeleteEffects* effects, DeletionType type);
212
213  // Schedules a call to DoExpireIteration.
214  void ScheduleExpire();
215
216  // Calls ExpireSomeOldHistory to expire some amount of old history, according
217  // to the items in work queue, and schedules another call to happen in the
218  // future.
219  void DoExpireIteration();
220
221  // Tries to expire the oldest |max_visits| visits from history that are older
222  // than |time_threshold|. The return value indicates if we think there might
223  // be more history to expire with the current time threshold (it does not
224  // indicate success or failure).
225  bool ExpireSomeOldHistory(base::Time end_time,
226                             const ExpiringVisitsReader* reader,
227                             int max_visits);
228
229  // Tries to detect possible bad history or inconsistencies in the database
230  // and deletes items. For example, URLs with no visits.
231  void ParanoidExpireHistory();
232
233  // Returns the HistoryClient, blocking until the bookmarks are loaded. This
234  // may return NULL during testing.
235  HistoryClient* GetHistoryClient();
236
237  // Initializes periodic expiration work queue by populating it with with tasks
238  // for all known readers.
239  void InitWorkQueue();
240
241  // Returns the reader for all visits. This method is only used by the unit
242  // tests.
243  const ExpiringVisitsReader* GetAllVisitsReader();
244
245  // Returns the reader for AUTO_SUBFRAME visits. This method is only used by
246  // the unit tests.
247  const ExpiringVisitsReader* GetAutoSubframeVisitsReader();
248
249  // Non-owning pointer to the notification delegate (guaranteed non-NULL).
250  BroadcastNotificationDelegate* delegate_;
251
252  // Non-owning pointers to the databases we deal with (MAY BE NULL).
253  HistoryDatabase* main_db_;       // Main history database.
254  ThumbnailDatabase* thumb_db_;    // Thumbnails and favicons.
255
256  // Used to generate runnable methods to do timers on this class. They will be
257  // automatically canceled when this class is deleted.
258  base::WeakPtrFactory<ExpireHistoryBackend> weak_factory_;
259
260  // The threshold for "old" history where we will automatically delete it.
261  base::TimeDelta expiration_threshold_;
262
263  // List of all distinct types of readers. This list is used to populate the
264  // work queue.
265  ExpiringVisitsReaders readers_;
266
267  // Work queue for periodic expiration tasks, used by DoExpireIteration() to
268  // determine what to do at an iteration, as well as populate it for future
269  // iterations.
270  std::queue<const ExpiringVisitsReader*> work_queue_;
271
272  // Readers for various types of visits.
273  // TODO(dglazkov): If you are adding another one, please consider reorganizing
274  // into a map.
275  scoped_ptr<ExpiringVisitsReader> all_visits_reader_;
276  scoped_ptr<ExpiringVisitsReader> auto_subframe_visits_reader_;
277
278  // The HistoryClient; may be NULL.
279  //
280  // Use GetHistoryClient to access this, which makes sure the bookmarks are
281  // loaded before returning.
282  HistoryClient* history_client_;
283
284  DISALLOW_COPY_AND_ASSIGN(ExpireHistoryBackend);
285};
286
287}  // namespace history
288
289#endif  // CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_
290