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 #include "chrome/browser/history/expire_history_backend.h" | 5 #include "chrome/browser/history/expire_history_backend.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <limits> | 9 #include <limits> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
14 #include "base/files/file_enumerator.h" | 14 #include "base/files/file_enumerator.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
17 #include "chrome/browser/bookmarks/bookmark_service.h" | 17 #include "chrome/browser/bookmarks/bookmark_service.h" |
18 #include "chrome/browser/chrome_notification_types.h" | 18 #include "chrome/browser/chrome_notification_types.h" |
19 #include "chrome/browser/history/archived_database.h" | 19 #include "chrome/browser/history/archived_database.h" |
20 #include "chrome/browser/history/history_database.h" | 20 #include "chrome/browser/history/history_database.h" |
21 #include "chrome/browser/history/history_notifications.h" | 21 #include "chrome/browser/history/history_notifications.h" |
| 22 #include "chrome/browser/history/text_database.h" |
| 23 #include "chrome/browser/history/text_database_manager.h" |
22 #include "chrome/browser/history/thumbnail_database.h" | 24 #include "chrome/browser/history/thumbnail_database.h" |
23 | 25 |
24 using base::Time; | 26 using base::Time; |
25 using base::TimeDelta; | 27 using base::TimeDelta; |
26 | 28 |
27 namespace history { | 29 namespace history { |
28 | 30 |
29 namespace { | 31 namespace { |
30 | 32 |
31 // The number of days by which the expiration threshold is advanced for items | 33 // The number of days by which the expiration threshold is advanced for items |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 URLRows deleted_urls; | 165 URLRows deleted_urls; |
164 | 166 |
165 // The list of all favicon IDs that the affected URLs had. Favicons will be | 167 // The list of all favicon IDs that the affected URLs had. Favicons will be |
166 // shared between all URLs with the same favicon, so this is the set of IDs | 168 // shared between all URLs with the same favicon, so this is the set of IDs |
167 // that we will need to check when the delete operations are complete. | 169 // that we will need to check when the delete operations are complete. |
168 std::set<chrome::FaviconID> affected_favicons; | 170 std::set<chrome::FaviconID> affected_favicons; |
169 | 171 |
170 // The list of all favicon urls that were actually deleted from the thumbnail | 172 // The list of all favicon urls that were actually deleted from the thumbnail |
171 // db. | 173 // db. |
172 std::set<GURL> expired_favicons; | 174 std::set<GURL> expired_favicons; |
| 175 |
| 176 // Tracks the set of databases that have changed so we can optimize when |
| 177 // when we're done. |
| 178 TextDatabaseManager::ChangeSet text_db_changes; |
173 }; | 179 }; |
174 | 180 |
175 ExpireHistoryBackend::ExpireHistoryBackend( | 181 ExpireHistoryBackend::ExpireHistoryBackend( |
176 BroadcastNotificationDelegate* delegate, | 182 BroadcastNotificationDelegate* delegate, |
177 BookmarkService* bookmark_service) | 183 BookmarkService* bookmark_service) |
178 : delegate_(delegate), | 184 : delegate_(delegate), |
179 main_db_(NULL), | 185 main_db_(NULL), |
180 archived_db_(NULL), | 186 archived_db_(NULL), |
181 thumb_db_(NULL), | 187 thumb_db_(NULL), |
| 188 text_db_(NULL), |
182 weak_factory_(this), | 189 weak_factory_(this), |
183 bookmark_service_(bookmark_service) { | 190 bookmark_service_(bookmark_service) { |
184 } | 191 } |
185 | 192 |
186 ExpireHistoryBackend::~ExpireHistoryBackend() { | 193 ExpireHistoryBackend::~ExpireHistoryBackend() { |
187 } | 194 } |
188 | 195 |
189 void ExpireHistoryBackend::SetDatabases(HistoryDatabase* main_db, | 196 void ExpireHistoryBackend::SetDatabases(HistoryDatabase* main_db, |
190 ArchivedDatabase* archived_db, | 197 ArchivedDatabase* archived_db, |
191 ThumbnailDatabase* thumb_db) { | 198 ThumbnailDatabase* thumb_db, |
| 199 TextDatabaseManager* text_db) { |
192 main_db_ = main_db; | 200 main_db_ = main_db; |
193 archived_db_ = archived_db; | 201 archived_db_ = archived_db; |
194 thumb_db_ = thumb_db; | 202 thumb_db_ = thumb_db; |
| 203 text_db_ = text_db; |
195 } | 204 } |
196 | 205 |
197 void ExpireHistoryBackend::DeleteURL(const GURL& url) { | 206 void ExpireHistoryBackend::DeleteURL(const GURL& url) { |
198 DeleteURLs(std::vector<GURL>(1, url)); | 207 DeleteURLs(std::vector<GURL>(1, url)); |
199 } | 208 } |
200 | 209 |
201 void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) { | 210 void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) { |
202 if (!main_db_) | 211 if (!main_db_) |
203 return; | 212 return; |
204 | 213 |
(...skipping 21 matching lines...) Expand all Loading... |
226 BookmarkService* bookmark_service = GetBookmarkService(); | 235 BookmarkService* bookmark_service = GetBookmarkService(); |
227 bool is_bookmarked = | 236 bool is_bookmarked = |
228 (bookmark_service && bookmark_service->IsBookmarked(*url)); | 237 (bookmark_service && bookmark_service->IsBookmarked(*url)); |
229 | 238 |
230 DeleteOneURL(url_row, is_bookmarked, &dependencies); | 239 DeleteOneURL(url_row, is_bookmarked, &dependencies); |
231 } | 240 } |
232 | 241 |
233 DeleteFaviconsIfPossible(dependencies.affected_favicons, | 242 DeleteFaviconsIfPossible(dependencies.affected_favicons, |
234 &dependencies.expired_favicons); | 243 &dependencies.expired_favicons); |
235 | 244 |
| 245 if (text_db_) |
| 246 text_db_->OptimizeChangedDatabases(dependencies.text_db_changes); |
| 247 |
236 BroadcastDeleteNotifications(&dependencies, DELETION_USER_INITIATED); | 248 BroadcastDeleteNotifications(&dependencies, DELETION_USER_INITIATED); |
237 } | 249 } |
238 | 250 |
239 void ExpireHistoryBackend::ExpireHistoryBetween( | 251 void ExpireHistoryBackend::ExpireHistoryBetween( |
240 const std::set<GURL>& restrict_urls, Time begin_time, Time end_time) { | 252 const std::set<GURL>& restrict_urls, Time begin_time, Time end_time) { |
241 if (!main_db_) | 253 if (!main_db_) |
242 return; | 254 return; |
243 | 255 |
| 256 // There may be stuff in the text database manager's temporary cache. |
| 257 if (text_db_) |
| 258 text_db_->DeleteFromUncommitted(restrict_urls, begin_time, end_time); |
| 259 |
244 // Find the affected visits and delete them. | 260 // Find the affected visits and delete them. |
245 // TODO(brettw): bug 1171164: We should query the archived database here, too. | 261 // TODO(brettw): bug 1171164: We should query the archived database here, too. |
246 VisitVector visits; | 262 VisitVector visits; |
247 main_db_->GetAllVisitsInRange(begin_time, end_time, 0, &visits); | 263 main_db_->GetAllVisitsInRange(begin_time, end_time, 0, &visits); |
248 if (!restrict_urls.empty()) { | 264 if (!restrict_urls.empty()) { |
249 std::set<URLID> url_ids; | 265 std::set<URLID> url_ids; |
250 for (std::set<GURL>::const_iterator url = restrict_urls.begin(); | 266 for (std::set<GURL>::const_iterator url = restrict_urls.begin(); |
251 url != restrict_urls.end(); ++url) | 267 url != restrict_urls.end(); ++url) |
252 url_ids.insert(main_db_->GetRowForURL(*url, NULL)); | 268 url_ids.insert(main_db_->GetRowForURL(*url, NULL)); |
253 VisitVector all_visits; | 269 VisitVector all_visits; |
(...skipping 13 matching lines...) Expand all Loading... |
267 // duplicates, i.e. each member must be earlier than the one before | 283 // duplicates, i.e. each member must be earlier than the one before |
268 // it. | 284 // it. |
269 DCHECK( | 285 DCHECK( |
270 std::adjacent_find( | 286 std::adjacent_find( |
271 times.begin(), times.end(), std::less_equal<base::Time>()) == | 287 times.begin(), times.end(), std::less_equal<base::Time>()) == |
272 times.end()); | 288 times.end()); |
273 | 289 |
274 if (!main_db_) | 290 if (!main_db_) |
275 return; | 291 return; |
276 | 292 |
| 293 // There may be stuff in the text database manager's temporary cache. |
| 294 if (text_db_) |
| 295 text_db_->DeleteFromUncommittedForTimes(times); |
| 296 |
277 // Find the affected visits and delete them. | 297 // Find the affected visits and delete them. |
278 // TODO(brettw): bug 1171164: We should query the archived database here, too. | 298 // TODO(brettw): bug 1171164: We should query the archived database here, too. |
279 VisitVector visits; | 299 VisitVector visits; |
280 main_db_->GetVisitsForTimes(times, &visits); | 300 main_db_->GetVisitsForTimes(times, &visits); |
281 ExpireVisits(visits); | 301 ExpireVisits(visits); |
282 } | 302 } |
283 | 303 |
284 void ExpireHistoryBackend::ExpireVisits(const VisitVector& visits) { | 304 void ExpireHistoryBackend::ExpireVisits(const VisitVector& visits) { |
285 if (visits.empty()) | 305 if (visits.empty()) |
286 return; | 306 return; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 // For now, we explicitly add all known readers. If we come up with more | 361 // For now, we explicitly add all known readers. If we come up with more |
342 // reader types (in case we want to expire different types of visits in | 362 // reader types (in case we want to expire different types of visits in |
343 // different ways), we can make it be populated by creator/owner of | 363 // different ways), we can make it be populated by creator/owner of |
344 // ExpireHistoryBackend. | 364 // ExpireHistoryBackend. |
345 readers_.push_back(GetAllVisitsReader()); | 365 readers_.push_back(GetAllVisitsReader()); |
346 readers_.push_back(GetAutoSubframeVisitsReader()); | 366 readers_.push_back(GetAutoSubframeVisitsReader()); |
347 | 367 |
348 // Initialize the queue with all tasks for the first set of iterations. | 368 // Initialize the queue with all tasks for the first set of iterations. |
349 InitWorkQueue(); | 369 InitWorkQueue(); |
350 ScheduleArchive(); | 370 ScheduleArchive(); |
| 371 ScheduleExpireHistoryIndexFiles(); |
351 } | 372 } |
352 | 373 |
353 void ExpireHistoryBackend::DeleteFaviconsIfPossible( | 374 void ExpireHistoryBackend::DeleteFaviconsIfPossible( |
354 const std::set<chrome::FaviconID>& favicon_set, | 375 const std::set<chrome::FaviconID>& favicon_set, |
355 std::set<GURL>* expired_favicons) { | 376 std::set<GURL>* expired_favicons) { |
356 if (!thumb_db_) | 377 if (!thumb_db_) |
357 return; | 378 return; |
358 | 379 |
359 for (std::set<chrome::FaviconID>::const_iterator i = favicon_set.begin(); | 380 for (std::set<chrome::FaviconID>::const_iterator i = favicon_set.begin(); |
360 i != favicon_set.end(); ++i) { | 381 i != favicon_set.end(); ++i) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 void ExpireHistoryBackend::DeleteVisitRelatedInfo( | 415 void ExpireHistoryBackend::DeleteVisitRelatedInfo( |
395 const VisitVector& visits, | 416 const VisitVector& visits, |
396 DeleteDependencies* dependencies) { | 417 DeleteDependencies* dependencies) { |
397 for (size_t i = 0; i < visits.size(); i++) { | 418 for (size_t i = 0; i < visits.size(); i++) { |
398 // Delete the visit itself. | 419 // Delete the visit itself. |
399 main_db_->DeleteVisit(visits[i]); | 420 main_db_->DeleteVisit(visits[i]); |
400 | 421 |
401 // Add the URL row to the affected URL list. | 422 // Add the URL row to the affected URL list. |
402 std::map<URLID, URLRow>::const_iterator found = | 423 std::map<URLID, URLRow>::const_iterator found = |
403 dependencies->affected_urls.find(visits[i].url_id); | 424 dependencies->affected_urls.find(visits[i].url_id); |
| 425 const URLRow* cur_row = NULL; |
404 if (found == dependencies->affected_urls.end()) { | 426 if (found == dependencies->affected_urls.end()) { |
405 URLRow row; | 427 URLRow row; |
406 if (!main_db_->GetURLRow(visits[i].url_id, &row)) | 428 if (!main_db_->GetURLRow(visits[i].url_id, &row)) |
407 continue; | 429 continue; |
408 dependencies->affected_urls[visits[i].url_id] = row; | 430 dependencies->affected_urls[visits[i].url_id] = row; |
| 431 cur_row = &dependencies->affected_urls[visits[i].url_id]; |
| 432 } else { |
| 433 cur_row = &found->second; |
| 434 } |
| 435 |
| 436 // Delete any associated full-text indexed data. |
| 437 if (visits[i].is_indexed && text_db_) { |
| 438 text_db_->DeletePageData(visits[i].visit_time, cur_row->url(), |
| 439 &dependencies->text_db_changes); |
409 } | 440 } |
410 } | 441 } |
411 } | 442 } |
412 | 443 |
413 void ExpireHistoryBackend::DeleteOneURL( | 444 void ExpireHistoryBackend::DeleteOneURL( |
414 const URLRow& url_row, | 445 const URLRow& url_row, |
415 bool is_bookmarked, | 446 bool is_bookmarked, |
416 DeleteDependencies* dependencies) { | 447 DeleteDependencies* dependencies) { |
417 main_db_->DeleteSegmentForURL(url_row.id()); | 448 main_db_->DeleteSegmentForURL(url_row.id()); |
418 | 449 |
| 450 // The URL may be in the text database manager's temporary cache. |
| 451 if (text_db_) { |
| 452 std::set<GURL> restrict_urls; |
| 453 restrict_urls.insert(url_row.url()); |
| 454 text_db_->DeleteFromUncommitted(restrict_urls, base::Time(), base::Time()); |
| 455 } |
| 456 |
419 if (!is_bookmarked) { | 457 if (!is_bookmarked) { |
420 dependencies->deleted_urls.push_back(url_row); | 458 dependencies->deleted_urls.push_back(url_row); |
421 | 459 |
422 // Delete stuff that references this URL. | 460 // Delete stuff that references this URL. |
423 if (thumb_db_) { | 461 if (thumb_db_) { |
424 thumb_db_->DeleteThumbnail(url_row.id()); | 462 thumb_db_->DeleteThumbnail(url_row.id()); |
425 | 463 |
426 // Collect shared information. | 464 // Collect shared information. |
427 std::vector<IconMapping> icon_mappings; | 465 std::vector<IconMapping> icon_mappings; |
428 if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) { | 466 if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) { |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 // to not do anything if nothing was deleted. | 715 // to not do anything if nothing was deleted. |
678 BroadcastDeleteNotifications(&deleted_dependencies, DELETION_ARCHIVED); | 716 BroadcastDeleteNotifications(&deleted_dependencies, DELETION_ARCHIVED); |
679 | 717 |
680 return more_to_expire; | 718 return more_to_expire; |
681 } | 719 } |
682 | 720 |
683 void ExpireHistoryBackend::ParanoidExpireHistory() { | 721 void ExpireHistoryBackend::ParanoidExpireHistory() { |
684 // TODO(brettw): Bug 1067331: write this to clean up any errors. | 722 // TODO(brettw): Bug 1067331: write this to clean up any errors. |
685 } | 723 } |
686 | 724 |
| 725 void ExpireHistoryBackend::ScheduleExpireHistoryIndexFiles() { |
| 726 if (!text_db_) { |
| 727 // Can't expire old history index files because we |
| 728 // don't know where they're located. |
| 729 return; |
| 730 } |
| 731 |
| 732 TimeDelta delay = TimeDelta::FromMinutes(kIndexExpirationDelayMin); |
| 733 base::MessageLoop::current()->PostDelayedTask( |
| 734 FROM_HERE, |
| 735 base::Bind(&ExpireHistoryBackend::DoExpireHistoryIndexFiles, |
| 736 weak_factory_.GetWeakPtr()), |
| 737 delay); |
| 738 } |
| 739 |
| 740 void ExpireHistoryBackend::DoExpireHistoryIndexFiles() { |
| 741 if (!text_db_) { |
| 742 // The text database may have been closed since the task was scheduled. |
| 743 return; |
| 744 } |
| 745 |
| 746 Time::Exploded exploded; |
| 747 Time::Now().LocalExplode(&exploded); |
| 748 int cutoff_month = |
| 749 exploded.year * 12 + exploded.month - kStoreHistoryIndexesForMonths; |
| 750 TextDatabase::DBIdent cutoff_id = |
| 751 (cutoff_month / 12) * 100 + (cutoff_month % 12); |
| 752 |
| 753 base::FilePath::StringType history_index_files_pattern = |
| 754 TextDatabase::file_base(); |
| 755 history_index_files_pattern.append(FILE_PATH_LITERAL("*")); |
| 756 base::FileEnumerator file_enumerator( |
| 757 text_db_->GetDir(), false, base::FileEnumerator::FILES, |
| 758 history_index_files_pattern); |
| 759 for (base::FilePath file = file_enumerator.Next(); !file.empty(); |
| 760 file = file_enumerator.Next()) { |
| 761 TextDatabase::DBIdent file_id = TextDatabase::FileNameToID(file); |
| 762 if (file_id < cutoff_id) |
| 763 sql::Connection::Delete(file); |
| 764 } |
| 765 } |
| 766 |
687 BookmarkService* ExpireHistoryBackend::GetBookmarkService() { | 767 BookmarkService* ExpireHistoryBackend::GetBookmarkService() { |
688 // We use the bookmark service to determine if a URL is bookmarked. The | 768 // We use the bookmark service to determine if a URL is bookmarked. The |
689 // bookmark service is loaded on a separate thread and may not be done by the | 769 // bookmark service is loaded on a separate thread and may not be done by the |
690 // time we get here. We therefor block until the bookmarks have finished | 770 // time we get here. We therefor block until the bookmarks have finished |
691 // loading. | 771 // loading. |
692 if (bookmark_service_) | 772 if (bookmark_service_) |
693 bookmark_service_->BlockTillLoaded(); | 773 bookmark_service_->BlockTillLoaded(); |
694 return bookmark_service_; | 774 return bookmark_service_; |
695 } | 775 } |
696 | 776 |
697 } // namespace history | 777 } // namespace history |
OLD | NEW |