| 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" | |
| 24 #include "chrome/browser/history/thumbnail_database.h" | 22 #include "chrome/browser/history/thumbnail_database.h" |
| 25 | 23 |
| 26 using base::Time; | 24 using base::Time; |
| 27 using base::TimeDelta; | 25 using base::TimeDelta; |
| 28 | 26 |
| 29 namespace history { | 27 namespace history { |
| 30 | 28 |
| 31 namespace { | 29 namespace { |
| 32 | 30 |
| 33 // The number of days by which the expiration threshold is advanced for items | 31 // 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... |
| 165 URLRows deleted_urls; | 163 URLRows deleted_urls; |
| 166 | 164 |
| 167 // The list of all favicon IDs that the affected URLs had. Favicons will be | 165 // The list of all favicon IDs that the affected URLs had. Favicons will be |
| 168 // shared between all URLs with the same favicon, so this is the set of IDs | 166 // shared between all URLs with the same favicon, so this is the set of IDs |
| 169 // that we will need to check when the delete operations are complete. | 167 // that we will need to check when the delete operations are complete. |
| 170 std::set<chrome::FaviconID> affected_favicons; | 168 std::set<chrome::FaviconID> affected_favicons; |
| 171 | 169 |
| 172 // The list of all favicon urls that were actually deleted from the thumbnail | 170 // The list of all favicon urls that were actually deleted from the thumbnail |
| 173 // db. | 171 // db. |
| 174 std::set<GURL> expired_favicons; | 172 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; | |
| 179 }; | 173 }; |
| 180 | 174 |
| 181 ExpireHistoryBackend::ExpireHistoryBackend( | 175 ExpireHistoryBackend::ExpireHistoryBackend( |
| 182 BroadcastNotificationDelegate* delegate, | 176 BroadcastNotificationDelegate* delegate, |
| 183 BookmarkService* bookmark_service) | 177 BookmarkService* bookmark_service) |
| 184 : delegate_(delegate), | 178 : delegate_(delegate), |
| 185 main_db_(NULL), | 179 main_db_(NULL), |
| 186 archived_db_(NULL), | 180 archived_db_(NULL), |
| 187 thumb_db_(NULL), | 181 thumb_db_(NULL), |
| 188 text_db_(NULL), | |
| 189 weak_factory_(this), | 182 weak_factory_(this), |
| 190 bookmark_service_(bookmark_service) { | 183 bookmark_service_(bookmark_service) { |
| 191 } | 184 } |
| 192 | 185 |
| 193 ExpireHistoryBackend::~ExpireHistoryBackend() { | 186 ExpireHistoryBackend::~ExpireHistoryBackend() { |
| 194 } | 187 } |
| 195 | 188 |
| 196 void ExpireHistoryBackend::SetDatabases(HistoryDatabase* main_db, | 189 void ExpireHistoryBackend::SetDatabases(HistoryDatabase* main_db, |
| 197 ArchivedDatabase* archived_db, | 190 ArchivedDatabase* archived_db, |
| 198 ThumbnailDatabase* thumb_db, | 191 ThumbnailDatabase* thumb_db) { |
| 199 TextDatabaseManager* text_db) { | |
| 200 main_db_ = main_db; | 192 main_db_ = main_db; |
| 201 archived_db_ = archived_db; | 193 archived_db_ = archived_db; |
| 202 thumb_db_ = thumb_db; | 194 thumb_db_ = thumb_db; |
| 203 text_db_ = text_db; | |
| 204 } | 195 } |
| 205 | 196 |
| 206 void ExpireHistoryBackend::DeleteURL(const GURL& url) { | 197 void ExpireHistoryBackend::DeleteURL(const GURL& url) { |
| 207 DeleteURLs(std::vector<GURL>(1, url)); | 198 DeleteURLs(std::vector<GURL>(1, url)); |
| 208 } | 199 } |
| 209 | 200 |
| 210 void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) { | 201 void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) { |
| 211 if (!main_db_) | 202 if (!main_db_) |
| 212 return; | 203 return; |
| 213 | 204 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 235 BookmarkService* bookmark_service = GetBookmarkService(); | 226 BookmarkService* bookmark_service = GetBookmarkService(); |
| 236 bool is_bookmarked = | 227 bool is_bookmarked = |
| 237 (bookmark_service && bookmark_service->IsBookmarked(*url)); | 228 (bookmark_service && bookmark_service->IsBookmarked(*url)); |
| 238 | 229 |
| 239 DeleteOneURL(url_row, is_bookmarked, &dependencies); | 230 DeleteOneURL(url_row, is_bookmarked, &dependencies); |
| 240 } | 231 } |
| 241 | 232 |
| 242 DeleteFaviconsIfPossible(dependencies.affected_favicons, | 233 DeleteFaviconsIfPossible(dependencies.affected_favicons, |
| 243 &dependencies.expired_favicons); | 234 &dependencies.expired_favicons); |
| 244 | 235 |
| 245 if (text_db_) | |
| 246 text_db_->OptimizeChangedDatabases(dependencies.text_db_changes); | |
| 247 | |
| 248 BroadcastDeleteNotifications(&dependencies, DELETION_USER_INITIATED); | 236 BroadcastDeleteNotifications(&dependencies, DELETION_USER_INITIATED); |
| 249 } | 237 } |
| 250 | 238 |
| 251 void ExpireHistoryBackend::ExpireHistoryBetween( | 239 void ExpireHistoryBackend::ExpireHistoryBetween( |
| 252 const std::set<GURL>& restrict_urls, Time begin_time, Time end_time) { | 240 const std::set<GURL>& restrict_urls, Time begin_time, Time end_time) { |
| 253 if (!main_db_) | 241 if (!main_db_) |
| 254 return; | 242 return; |
| 255 | 243 |
| 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 | |
| 260 // Find the affected visits and delete them. | 244 // Find the affected visits and delete them. |
| 261 // TODO(brettw): bug 1171164: We should query the archived database here, too. | 245 // TODO(brettw): bug 1171164: We should query the archived database here, too. |
| 262 VisitVector visits; | 246 VisitVector visits; |
| 263 main_db_->GetAllVisitsInRange(begin_time, end_time, 0, &visits); | 247 main_db_->GetAllVisitsInRange(begin_time, end_time, 0, &visits); |
| 264 if (!restrict_urls.empty()) { | 248 if (!restrict_urls.empty()) { |
| 265 std::set<URLID> url_ids; | 249 std::set<URLID> url_ids; |
| 266 for (std::set<GURL>::const_iterator url = restrict_urls.begin(); | 250 for (std::set<GURL>::const_iterator url = restrict_urls.begin(); |
| 267 url != restrict_urls.end(); ++url) | 251 url != restrict_urls.end(); ++url) |
| 268 url_ids.insert(main_db_->GetRowForURL(*url, NULL)); | 252 url_ids.insert(main_db_->GetRowForURL(*url, NULL)); |
| 269 VisitVector all_visits; | 253 VisitVector all_visits; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 283 // duplicates, i.e. each member must be earlier than the one before | 267 // duplicates, i.e. each member must be earlier than the one before |
| 284 // it. | 268 // it. |
| 285 DCHECK( | 269 DCHECK( |
| 286 std::adjacent_find( | 270 std::adjacent_find( |
| 287 times.begin(), times.end(), std::less_equal<base::Time>()) == | 271 times.begin(), times.end(), std::less_equal<base::Time>()) == |
| 288 times.end()); | 272 times.end()); |
| 289 | 273 |
| 290 if (!main_db_) | 274 if (!main_db_) |
| 291 return; | 275 return; |
| 292 | 276 |
| 293 // There may be stuff in the text database manager's temporary cache. | |
| 294 if (text_db_) | |
| 295 text_db_->DeleteFromUncommittedForTimes(times); | |
| 296 | |
| 297 // Find the affected visits and delete them. | 277 // Find the affected visits and delete them. |
| 298 // TODO(brettw): bug 1171164: We should query the archived database here, too. | 278 // TODO(brettw): bug 1171164: We should query the archived database here, too. |
| 299 VisitVector visits; | 279 VisitVector visits; |
| 300 main_db_->GetVisitsForTimes(times, &visits); | 280 main_db_->GetVisitsForTimes(times, &visits); |
| 301 ExpireVisits(visits); | 281 ExpireVisits(visits); |
| 302 } | 282 } |
| 303 | 283 |
| 304 void ExpireHistoryBackend::ExpireVisits(const VisitVector& visits) { | 284 void ExpireHistoryBackend::ExpireVisits(const VisitVector& visits) { |
| 305 if (visits.empty()) | 285 if (visits.empty()) |
| 306 return; | 286 return; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 // For now, we explicitly add all known readers. If we come up with more | 341 // For now, we explicitly add all known readers. If we come up with more |
| 362 // reader types (in case we want to expire different types of visits in | 342 // reader types (in case we want to expire different types of visits in |
| 363 // different ways), we can make it be populated by creator/owner of | 343 // different ways), we can make it be populated by creator/owner of |
| 364 // ExpireHistoryBackend. | 344 // ExpireHistoryBackend. |
| 365 readers_.push_back(GetAllVisitsReader()); | 345 readers_.push_back(GetAllVisitsReader()); |
| 366 readers_.push_back(GetAutoSubframeVisitsReader()); | 346 readers_.push_back(GetAutoSubframeVisitsReader()); |
| 367 | 347 |
| 368 // Initialize the queue with all tasks for the first set of iterations. | 348 // Initialize the queue with all tasks for the first set of iterations. |
| 369 InitWorkQueue(); | 349 InitWorkQueue(); |
| 370 ScheduleArchive(); | 350 ScheduleArchive(); |
| 371 ScheduleExpireHistoryIndexFiles(); | |
| 372 } | 351 } |
| 373 | 352 |
| 374 void ExpireHistoryBackend::DeleteFaviconsIfPossible( | 353 void ExpireHistoryBackend::DeleteFaviconsIfPossible( |
| 375 const std::set<chrome::FaviconID>& favicon_set, | 354 const std::set<chrome::FaviconID>& favicon_set, |
| 376 std::set<GURL>* expired_favicons) { | 355 std::set<GURL>* expired_favicons) { |
| 377 if (!thumb_db_) | 356 if (!thumb_db_) |
| 378 return; | 357 return; |
| 379 | 358 |
| 380 for (std::set<chrome::FaviconID>::const_iterator i = favicon_set.begin(); | 359 for (std::set<chrome::FaviconID>::const_iterator i = favicon_set.begin(); |
| 381 i != favicon_set.end(); ++i) { | 360 i != favicon_set.end(); ++i) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 void ExpireHistoryBackend::DeleteVisitRelatedInfo( | 394 void ExpireHistoryBackend::DeleteVisitRelatedInfo( |
| 416 const VisitVector& visits, | 395 const VisitVector& visits, |
| 417 DeleteDependencies* dependencies) { | 396 DeleteDependencies* dependencies) { |
| 418 for (size_t i = 0; i < visits.size(); i++) { | 397 for (size_t i = 0; i < visits.size(); i++) { |
| 419 // Delete the visit itself. | 398 // Delete the visit itself. |
| 420 main_db_->DeleteVisit(visits[i]); | 399 main_db_->DeleteVisit(visits[i]); |
| 421 | 400 |
| 422 // Add the URL row to the affected URL list. | 401 // Add the URL row to the affected URL list. |
| 423 std::map<URLID, URLRow>::const_iterator found = | 402 std::map<URLID, URLRow>::const_iterator found = |
| 424 dependencies->affected_urls.find(visits[i].url_id); | 403 dependencies->affected_urls.find(visits[i].url_id); |
| 425 const URLRow* cur_row = NULL; | |
| 426 if (found == dependencies->affected_urls.end()) { | 404 if (found == dependencies->affected_urls.end()) { |
| 427 URLRow row; | 405 URLRow row; |
| 428 if (!main_db_->GetURLRow(visits[i].url_id, &row)) | 406 if (!main_db_->GetURLRow(visits[i].url_id, &row)) |
| 429 continue; | 407 continue; |
| 430 dependencies->affected_urls[visits[i].url_id] = row; | 408 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); | |
| 440 } | 409 } |
| 441 } | 410 } |
| 442 } | 411 } |
| 443 | 412 |
| 444 void ExpireHistoryBackend::DeleteOneURL( | 413 void ExpireHistoryBackend::DeleteOneURL( |
| 445 const URLRow& url_row, | 414 const URLRow& url_row, |
| 446 bool is_bookmarked, | 415 bool is_bookmarked, |
| 447 DeleteDependencies* dependencies) { | 416 DeleteDependencies* dependencies) { |
| 448 main_db_->DeleteSegmentForURL(url_row.id()); | 417 main_db_->DeleteSegmentForURL(url_row.id()); |
| 449 | 418 |
| 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 | |
| 457 if (!is_bookmarked) { | 419 if (!is_bookmarked) { |
| 458 dependencies->deleted_urls.push_back(url_row); | 420 dependencies->deleted_urls.push_back(url_row); |
| 459 | 421 |
| 460 // Delete stuff that references this URL. | 422 // Delete stuff that references this URL. |
| 461 if (thumb_db_) { | 423 if (thumb_db_) { |
| 462 thumb_db_->DeleteThumbnail(url_row.id()); | 424 thumb_db_->DeleteThumbnail(url_row.id()); |
| 463 | 425 |
| 464 // Collect shared information. | 426 // Collect shared information. |
| 465 std::vector<IconMapping> icon_mappings; | 427 std::vector<IconMapping> icon_mappings; |
| 466 if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) { | 428 if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) { |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 // to not do anything if nothing was deleted. | 677 // to not do anything if nothing was deleted. |
| 716 BroadcastDeleteNotifications(&deleted_dependencies, DELETION_ARCHIVED); | 678 BroadcastDeleteNotifications(&deleted_dependencies, DELETION_ARCHIVED); |
| 717 | 679 |
| 718 return more_to_expire; | 680 return more_to_expire; |
| 719 } | 681 } |
| 720 | 682 |
| 721 void ExpireHistoryBackend::ParanoidExpireHistory() { | 683 void ExpireHistoryBackend::ParanoidExpireHistory() { |
| 722 // TODO(brettw): Bug 1067331: write this to clean up any errors. | 684 // TODO(brettw): Bug 1067331: write this to clean up any errors. |
| 723 } | 685 } |
| 724 | 686 |
| 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 | |
| 767 BookmarkService* ExpireHistoryBackend::GetBookmarkService() { | 687 BookmarkService* ExpireHistoryBackend::GetBookmarkService() { |
| 768 // We use the bookmark service to determine if a URL is bookmarked. The | 688 // We use the bookmark service to determine if a URL is bookmarked. The |
| 769 // bookmark service is loaded on a separate thread and may not be done by the | 689 // bookmark service is loaded on a separate thread and may not be done by the |
| 770 // time we get here. We therefor block until the bookmarks have finished | 690 // time we get here. We therefor block until the bookmarks have finished |
| 771 // loading. | 691 // loading. |
| 772 if (bookmark_service_) | 692 if (bookmark_service_) |
| 773 bookmark_service_->BlockTillLoaded(); | 693 bookmark_service_->BlockTillLoaded(); |
| 774 return bookmark_service_; | 694 return bookmark_service_; |
| 775 } | 695 } |
| 776 | 696 |
| 777 } // namespace history | 697 } // namespace history |
| OLD | NEW |