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