Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: components/ntp_snippets/remote/ntp_snippets_service.cc

Issue 2386103009: NTPSnippetsService: Garbage collect orphaned images at startup. (Closed)
Patch Set: final comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "components/ntp_snippets/remote/ntp_snippets_service.h" 5 #include "components/ntp_snippets/remote/ntp_snippets_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iterator> 8 #include <iterator>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/memory/ptr_util.h"
13 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
14 #include "base/metrics/sparse_histogram.h" 15 #include "base/metrics/sparse_histogram.h"
15 #include "base/path_service.h" 16 #include "base/path_service.h"
16 #include "base/stl_util.h" 17 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/utf_string_conversions.h" 19 #include "base/strings/utf_string_conversions.h"
19 #include "base/task_runner_util.h" 20 #include "base/task_runner_util.h"
20 #include "base/time/time.h" 21 #include "base/time/time.h"
21 #include "base/values.h" 22 #include "base/values.h"
22 #include "components/data_use_measurement/core/data_use_user_data.h" 23 #include "components/data_use_measurement/core/data_use_user_data.h"
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 std::set<std::string> GetAllIDs(const NTPSnippet::PtrVector& snippets) { 123 std::set<std::string> GetAllIDs(const NTPSnippet::PtrVector& snippets) {
123 std::set<std::string> ids; 124 std::set<std::string> ids;
124 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) { 125 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) {
125 ids.insert(snippet->id()); 126 ids.insert(snippet->id());
126 for (const SnippetSource& source : snippet->sources()) 127 for (const SnippetSource& source : snippet->sources())
127 ids.insert(source.url.spec()); 128 ids.insert(source.url.spec());
128 } 129 }
129 return ids; 130 return ids;
130 } 131 }
131 132
132 std::set<std::string> GetMainIDs(const NTPSnippet::PtrVector& snippets) { 133 std::set<std::string> GetSnippetIDSet(const NTPSnippet::PtrVector& snippets) {
133 std::set<std::string> ids; 134 std::set<std::string> ids;
134 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) 135 for (const std::unique_ptr<NTPSnippet>& snippet : snippets)
135 ids.insert(snippet->id()); 136 ids.insert(snippet->id());
136 return ids; 137 return ids;
137 } 138 }
138 139
140 std::unique_ptr<std::vector<std::string>> GetSnippetIDVector(
141 const NTPSnippet::PtrVector& snippets) {
142 auto result = base::MakeUnique<std::vector<std::string>>();
143 for (const auto& snippet : snippets) {
144 result->push_back(snippet->id());
145 }
146 return result;
147 }
148
139 bool IsSnippetInSet(const std::unique_ptr<NTPSnippet>& snippet, 149 bool IsSnippetInSet(const std::unique_ptr<NTPSnippet>& snippet,
140 const std::set<std::string>& ids, 150 const std::set<std::string>& ids,
141 bool match_all_ids) { 151 bool match_all_ids) {
142 if (ids.count(snippet->id())) 152 if (ids.count(snippet->id()))
143 return true; 153 return true;
144 if (!match_all_ids) 154 if (!match_all_ids)
145 return false; 155 return false;
146 for (const SnippetSource& source : snippet->sources()) { 156 for (const SnippetSource& source : snippet->sources()) {
147 if (ids.count(source.url.spec())) 157 if (ids.count(source.url.spec()))
148 return true; 158 return true;
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 if (!initialized()) 385 if (!initialized())
376 return; 386 return;
377 387
378 if (categories_.find(category) == categories_.end()) 388 if (categories_.find(category) == categories_.end())
379 return; 389 return;
380 CategoryContent* content = &categories_[category]; 390 CategoryContent* content = &categories_[category];
381 if (content->snippets.empty()) 391 if (content->snippets.empty())
382 return; 392 return;
383 393
384 if (category == articles_category_) { 394 if (category == articles_category_) {
385 database_->DeleteSnippets(content->snippets); 395 database_->DeleteSnippets(GetSnippetIDVector(content->snippets));
386 database_->DeleteImages(content->snippets); 396 database_->DeleteImages(GetSnippetIDVector(content->snippets));
387 } 397 }
388 content->snippets.clear(); 398 content->snippets.clear();
389 399
390 NotifyNewSuggestions(); 400 NotifyNewSuggestions();
391 } 401 }
392 402
393 void NTPSnippetsService::GetDismissedSuggestionsForDebugging( 403 void NTPSnippetsService::GetDismissedSuggestionsForDebugging(
394 Category category, 404 Category category,
395 const DismissedSuggestionsCallback& callback) { 405 const DismissedSuggestionsCallback& callback) {
396 DCHECK(categories_.find(category) != categories_.end()); 406 DCHECK(categories_.find(category) != categories_.end());
(...skipping 23 matching lines...) Expand all
420 430
421 if (!initialized()) 431 if (!initialized())
422 return; 432 return;
423 433
424 CategoryContent* content = &categories_[category]; 434 CategoryContent* content = &categories_[category];
425 if (content->dismissed.empty()) 435 if (content->dismissed.empty())
426 return; 436 return;
427 437
428 if (category == articles_category_) { 438 if (category == articles_category_) {
429 // The image got already deleted when the suggestion was dismissed. 439 // The image got already deleted when the suggestion was dismissed.
430 database_->DeleteSnippets(content->dismissed); 440 database_->DeleteSnippets(GetSnippetIDVector(content->dismissed));
431 } 441 }
432 content->dismissed.clear(); 442 content->dismissed.clear();
433 } 443 }
434 444
435 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { 445 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const {
436 // |suggestions_service_| can be null in tests. 446 // |suggestions_service_| can be null in tests.
437 if (!suggestions_service_) 447 if (!suggestions_service_)
438 return std::set<std::string>(); 448 return std::set<std::string>();
439 449
440 // TODO(treib): This should just call GetSnippetHostsFromPrefs. 450 // TODO(treib): This should just call GetSnippetHostsFromPrefs.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 else 510 else
501 content->snippets.emplace_back(std::move(snippet)); 511 content->snippets.emplace_back(std::move(snippet));
502 } 512 }
503 513
504 std::sort(content->snippets.begin(), content->snippets.end(), 514 std::sort(content->snippets.begin(), content->snippets.end(),
505 [](const std::unique_ptr<NTPSnippet>& lhs, 515 [](const std::unique_ptr<NTPSnippet>& lhs,
506 const std::unique_ptr<NTPSnippet>& rhs) { 516 const std::unique_ptr<NTPSnippet>& rhs) {
507 return lhs->score() > rhs->score(); 517 return lhs->score() > rhs->score();
508 }); 518 });
509 519
520 // TODO(tschumann): If I move ClearExpiredDismisedSnippets() to the beginning
521 // of the function, it essentially does nothing but tests are still green. Fix
522 // this!
510 ClearExpiredDismissedSnippets(); 523 ClearExpiredDismissedSnippets();
511 ClearOrphanedImages(); 524 ClearOrphanedImages();
512 FinishInitialization(); 525 FinishInitialization();
513 } 526 }
514 527
515 void NTPSnippetsService::OnDatabaseError() { 528 void NTPSnippetsService::OnDatabaseError() {
516 EnterState(State::ERROR_OCCURRED); 529 EnterState(State::ERROR_OCCURRED);
517 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); 530 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
518 } 531 }
519 532
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 categories_[category].provided_by_server = true; 599 categories_[category].provided_by_server = true;
587 600
588 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); 601 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount));
589 // TODO(sfiera): histograms for server categories. 602 // TODO(sfiera): histograms for server categories.
590 // Sparse histogram used because the number of snippets is small (bound by 603 // Sparse histogram used because the number of snippets is small (bound by
591 // kMaxSnippetCount). 604 // kMaxSnippetCount).
592 if (category == articles_category_) { 605 if (category == articles_category_) {
593 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", 606 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched",
594 fetched_category.snippets.size()); 607 fetched_category.snippets.size());
595 } 608 }
596
597 ReplaceSnippets(category, std::move(fetched_category.snippets)); 609 ReplaceSnippets(category, std::move(fetched_category.snippets));
598 } 610 }
599 } 611 }
600 612
601 for (const auto& item : categories_) { 613 for (const auto& item : categories_) {
602 Category category = item.first; 614 Category category = item.first;
603 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); 615 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
604 } 616 }
605 617
606 // TODO(sfiera): equivalent metrics for non-articles. 618 // TODO(sfiera): equivalent metrics for non-articles.
(...skipping 15 matching lines...) Expand all
622 if (snippets) 634 if (snippets)
623 RescheduleFetching(true); 635 RescheduleFetching(true);
624 } 636 }
625 637
626 void NTPSnippetsService::ArchiveSnippets(Category category, 638 void NTPSnippetsService::ArchiveSnippets(Category category,
627 NTPSnippet::PtrVector* to_archive) { 639 NTPSnippet::PtrVector* to_archive) {
628 CategoryContent* content = &categories_[category]; 640 CategoryContent* content = &categories_[category];
629 641
630 // TODO(sfiera): handle DB for non-articles too. 642 // TODO(sfiera): handle DB for non-articles too.
631 if (category == articles_category_) { 643 if (category == articles_category_) {
632 database_->DeleteSnippets(*to_archive); 644 database_->DeleteSnippets(GetSnippetIDVector(*to_archive));
633 // Do not delete the thumbnail images as they are still handy on open NTPs. 645 // Do not delete the thumbnail images as they are still handy on open NTPs.
634 } 646 }
635 647
636 // Archive previous snippets - move them at the beginning of the list. 648 // Archive previous snippets - move them at the beginning of the list.
637 content->archived.insert(content->archived.begin(), 649 content->archived.insert(content->archived.begin(),
638 std::make_move_iterator(to_archive->begin()), 650 std::make_move_iterator(to_archive->begin()),
639 std::make_move_iterator(to_archive->end())); 651 std::make_move_iterator(to_archive->end()));
640 Compact(to_archive); 652 Compact(to_archive);
641 653
642 // If there are more archived snippets than we want to keep, delete the 654 // If there are more archived snippets than we want to keep, delete the
643 // oldest ones by their fetch time (which are always in the back). 655 // oldest ones by their fetch time (which are always in the back).
644 if (content->archived.size() > kMaxArchivedSnippetCount) { 656 if (content->archived.size() > kMaxArchivedSnippetCount) {
645 NTPSnippet::PtrVector to_delete( 657 NTPSnippet::PtrVector to_delete(
646 std::make_move_iterator(content->archived.begin() + 658 std::make_move_iterator(content->archived.begin() +
647 kMaxArchivedSnippetCount), 659 kMaxArchivedSnippetCount),
648 std::make_move_iterator(content->archived.end())); 660 std::make_move_iterator(content->archived.end()));
649 content->archived.resize(kMaxArchivedSnippetCount); 661 content->archived.resize(kMaxArchivedSnippetCount);
650 if (category == articles_category_) 662 if (category == articles_category_)
651 database_->DeleteImages(to_delete); 663 database_->DeleteImages(GetSnippetIDVector(to_delete));
652 } 664 }
653 } 665 }
654 666
655 void NTPSnippetsService::ReplaceSnippets(Category category, 667 void NTPSnippetsService::ReplaceSnippets(Category category,
656 NTPSnippet::PtrVector new_snippets) { 668 NTPSnippet::PtrVector new_snippets) {
657 DCHECK(ready()); 669 DCHECK(ready());
658 CategoryContent* content = &categories_[category]; 670 CategoryContent* content = &categories_[category];
659 671
660 // Remove new snippets that have been dismissed. 672 // Remove new snippets that have been dismissed.
661 EraseMatchingSnippets(&new_snippets, GetAllIDs(content->dismissed), 673 EraseMatchingSnippets(&new_snippets, GetAllIDs(content->dismissed),
(...skipping 29 matching lines...) Expand all
691 num_snippets_dismissed); 703 num_snippets_dismissed);
692 } 704 }
693 } 705 }
694 706
695 // Do not touch the current set of snippets if the newly fetched one is empty. 707 // Do not touch the current set of snippets if the newly fetched one is empty.
696 if (new_snippets.empty()) 708 if (new_snippets.empty())
697 return; 709 return;
698 710
699 // Remove current snippets that have been fetched again. We do not need to 711 // Remove current snippets that have been fetched again. We do not need to
700 // archive those as they will be in the new current set. 712 // archive those as they will be in the new current set.
701 EraseMatchingSnippets(&content->snippets, GetMainIDs(new_snippets), 713 EraseMatchingSnippets(&content->snippets, GetSnippetIDSet(new_snippets),
702 /*match_all_ids=*/false); 714 /*match_all_ids=*/false);
703 715
704 ArchiveSnippets(category, &content->snippets); 716 ArchiveSnippets(category, &content->snippets);
705 717
706 // TODO(sfiera): handle DB for non-articles too. 718 // TODO(sfiera): handle DB for non-articles too.
707 if (category == articles_category_) { 719 if (category == articles_category_) {
708 // Save new articles to the DB. 720 // Save new articles to the DB.
709 database_->SaveSnippets(new_snippets); 721 database_->SaveSnippets(new_snippets);
710 } 722 }
711 723
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
745 // Move expired dismissed snippets over into |to_delete|. 757 // Move expired dismissed snippets over into |to_delete|.
746 for (std::unique_ptr<NTPSnippet>& snippet : content->dismissed) { 758 for (std::unique_ptr<NTPSnippet>& snippet : content->dismissed) {
747 if (snippet->expiry_date() <= now) 759 if (snippet->expiry_date() <= now)
748 to_delete.emplace_back(std::move(snippet)); 760 to_delete.emplace_back(std::move(snippet));
749 } 761 }
750 Compact(&content->dismissed); 762 Compact(&content->dismissed);
751 763
752 // Delete the removed article suggestions from the DB. 764 // Delete the removed article suggestions from the DB.
753 if (category == articles_category_) { 765 if (category == articles_category_) {
754 // The image got already deleted when the suggestion was dismissed. 766 // The image got already deleted when the suggestion was dismissed.
755 database_->DeleteSnippets(to_delete); 767 database_->DeleteSnippets(GetSnippetIDVector(to_delete));
756 } 768 }
757 769
758 if (content->snippets.empty() && content->dismissed.empty() && 770 if (content->snippets.empty() && content->dismissed.empty() &&
759 category != articles_category_ && !content->provided_by_server) { 771 category != articles_category_ && !content->provided_by_server) {
760 categories_to_erase.push_back(category); 772 categories_to_erase.push_back(category);
761 } 773 }
762 } 774 }
763 775
764 for (Category category : categories_to_erase) { 776 for (Category category : categories_to_erase) {
765 UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED); 777 UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED);
766 categories_.erase(category); 778 categories_.erase(category);
767 } 779 }
768 } 780 }
769 781
770 void NTPSnippetsService::ClearOrphanedImages() { 782 void NTPSnippetsService::ClearOrphanedImages() {
771 // TODO(jkrcal): Implement. crbug.com/649009 783 auto alive_snippets = base::MakeUnique<std::set<std::string>>();
784 for (const auto& snippet_ptr : categories_[articles_category_].snippets) {
785 alive_snippets->insert(snippet_ptr->id());
786 }
787 for (const auto& snippet_ptr : categories_[articles_category_].dismissed) {
788 alive_snippets->insert(snippet_ptr->id());
789 }
790 database_->GarbageCollectImages(std::move(alive_snippets));
772 } 791 }
773 792
774 void NTPSnippetsService::NukeAllSnippets() { 793 void NTPSnippetsService::NukeAllSnippets() {
775 std::vector<Category> categories_to_erase; 794 std::vector<Category> categories_to_erase;
776 795
777 // Empty the ARTICLES category and remove all others, since they may or may 796 // Empty the ARTICLES category and remove all others, since they may or may
778 // not be personalized. 797 // not be personalized.
779 for (const auto& item : categories_) { 798 for (const auto& item : categories_) {
780 Category category = item.first; 799 Category category = item.first;
781 800
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 } 1103 }
1085 1104
1086 NTPSnippetsService::CategoryContent::CategoryContent() = default; 1105 NTPSnippetsService::CategoryContent::CategoryContent() = default;
1087 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = 1106 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
1088 default; 1107 default;
1089 NTPSnippetsService::CategoryContent::~CategoryContent() = default; 1108 NTPSnippetsService::CategoryContent::~CategoryContent() = default;
1090 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: 1109 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent::
1091 operator=(CategoryContent&&) = default; 1110 operator=(CategoryContent&&) = default;
1092 1111
1093 } // namespace ntp_snippets 1112 } // namespace ntp_snippets
OLDNEW
« no previous file with comments | « components/ntp_snippets/remote/ntp_snippets_service.h ('k') | components/ntp_snippets/remote/ntp_snippets_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698