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

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

Issue 2051823003: [NTP Snippets] More reliable service initialization (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 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
« no previous file with comments | « components/ntp_snippets/ntp_snippets_service.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/ntp_snippets_service.h" 5 #include "components/ntp_snippets/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
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 database_(std::move(database)), 200 database_(std::move(database)),
201 fetch_after_load_(false) { 201 fetch_after_load_(false) {
202 // TODO(dgn) should be removed after branch point (https:://crbug.com/617585). 202 // TODO(dgn) should be removed after branch point (https:://crbug.com/617585).
203 ClearDeprecatedPrefs(); 203 ClearDeprecatedPrefs();
204 204
205 if (explicitly_disabled_) { 205 if (explicitly_disabled_) {
206 EnterState(State::DISABLED); 206 EnterState(State::DISABLED);
207 return; 207 return;
208 } 208 }
209 209
210 snippets_fetcher_->SetCallback(base::Bind( 210 // We transition to other states while finalizing the initialization, when the
211 &NTPSnippetsService::OnFetchFinished, base::Unretained(this))); 211 // database is done loading.
212
213 // |sync_service_| can be null in tests or if sync is disabled.
214 // This is a service we want to keep listening to all the time, independently
215 // from the state, since it will allow us to enable or disable the snippets
216 // service.
217 if (sync_service_)
218 sync_service_observer_.Add(sync_service_);
219
220 // Will trigger the transition to the READY state.
221 database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, 212 database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
222 base::Unretained(this))); 213 base::Unretained(this)));
223 } 214 }
224 215
225 NTPSnippetsService::~NTPSnippetsService() { 216 NTPSnippetsService::~NTPSnippetsService() {
226 DCHECK(state_ == State::SHUT_DOWN); 217 DCHECK(state_ == State::SHUT_DOWN);
227 } 218 }
228 219
229 // static 220 // static
230 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { 221 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 373
383 // static 374 // static
384 int NTPSnippetsService::GetMaxSnippetCountForTesting() { 375 int NTPSnippetsService::GetMaxSnippetCountForTesting() {
385 return kMaxSnippetCount; 376 return kMaxSnippetCount;
386 } 377 }
387 378
388 //////////////////////////////////////////////////////////////////////////////// 379 ////////////////////////////////////////////////////////////////////////////////
389 // Private methods 380 // Private methods
390 381
391 void NTPSnippetsService::OnStateChanged() { 382 void NTPSnippetsService::OnStateChanged() {
392 if (!initialized()) 383 if (state_ == State::SHUT_DOWN)
393 return; 384 return;
394 385
395 DVLOG(1) << "[OnStateChanged]"; 386 DVLOG(1) << "[OnStateChanged]";
396 EnterState(GetStateForDependenciesStatus()); 387 EnterState(GetStateForDependenciesStatus());
397 } 388 }
398 389
399 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { 390 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
400 DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN); 391 DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN);
401 if (state_ == State::SHUT_DOWN) 392 if (state_ == State::SHUT_DOWN)
402 return; 393 return;
403 394
404 DCHECK(snippets_.empty()); 395 DCHECK(snippets_.empty());
405 DCHECK(discarded_snippets_.empty()); 396 DCHECK(discarded_snippets_.empty());
406 for (std::unique_ptr<NTPSnippet>& snippet : snippets) { 397 for (std::unique_ptr<NTPSnippet>& snippet : snippets) {
407 if (snippet->is_discarded()) 398 if (snippet->is_discarded())
408 discarded_snippets_.emplace_back(std::move(snippet)); 399 discarded_snippets_.emplace_back(std::move(snippet));
409 else 400 else
410 snippets_.emplace_back(std::move(snippet)); 401 snippets_.emplace_back(std::move(snippet));
411 } 402 }
412 std::sort(snippets_.begin(), snippets_.end(), 403 std::sort(snippets_.begin(), snippets_.end(),
413 [](const std::unique_ptr<NTPSnippet>& lhs, 404 [](const std::unique_ptr<NTPSnippet>& lhs,
414 const std::unique_ptr<NTPSnippet>& rhs) { 405 const std::unique_ptr<NTPSnippet>& rhs) {
415 return lhs->score() > rhs->score(); 406 return lhs->score() > rhs->score();
416 }); 407 });
417 408
418 // Change state after we started loading the snippets. During startup, the 409 ClearExpiredSnippets();
419 // Sync service might not be completely loaded when we initialize this 410 FinishInitialization();
420 // service. Whether we had snippets in the last season is used to guess if
421 // we should enable the service or not. See |GetStateForDependenciesStatus|.
422 EnterState(GetStateForDependenciesStatus());
423
424 LoadingSnippetsFinished();
425
426 // Start a fetch if we don't have any snippets yet, or a fetch was requested
427 // earlier.
428 if (snippets_.empty() || fetch_after_load_) {
429 fetch_after_load_ = false;
430 FetchSnippets();
431 }
432 } 411 }
433 412
434 void NTPSnippetsService::OnSuggestionsChanged( 413 void NTPSnippetsService::OnSuggestionsChanged(
435 const SuggestionsProfile& suggestions) { 414 const SuggestionsProfile& suggestions) {
436 DCHECK(initialized()); 415 DCHECK(initialized());
437 416
438 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); 417 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions);
439 if (hosts == GetSnippetHostsFromPrefs()) 418 if (hosts == GetSnippetHostsFromPrefs())
440 return; 419 return;
441 420
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 } 531 }
553 532
554 void NTPSnippetsService::StoreSnippetHostsToPrefs( 533 void NTPSnippetsService::StoreSnippetHostsToPrefs(
555 const std::set<std::string>& hosts) { 534 const std::set<std::string>& hosts) {
556 base::ListValue list; 535 base::ListValue list;
557 for (const std::string& host : hosts) 536 for (const std::string& host : hosts)
558 list.AppendString(host); 537 list.AppendString(host);
559 pref_service_->Set(prefs::kSnippetHosts, list); 538 pref_service_->Set(prefs::kSnippetHosts, list);
560 } 539 }
561 540
562 void NTPSnippetsService::LoadingSnippetsFinished() { 541 void NTPSnippetsService::ClearExpiredSnippets() {
563 DCHECK(ready());
564
565 // Remove expired snippets.
566 base::Time expiry = base::Time::Now(); 542 base::Time expiry = base::Time::Now();
567 543
568 // Move expired snippets over into |to_delete|. 544 // Move expired snippets over into |to_delete|.
569 NTPSnippet::PtrVector to_delete; 545 NTPSnippet::PtrVector to_delete;
570 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) { 546 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
571 if (snippet->expiry_date() <= expiry) 547 if (snippet->expiry_date() <= expiry)
572 to_delete.emplace_back(std::move(snippet)); 548 to_delete.emplace_back(std::move(snippet));
573 } 549 }
574 Compact(&snippets_); 550 Compact(&snippets_);
575 551
576 // If there are still more snippets than we want to show, move the extra ones
577 // over into |to_delete| as well.
578 if (snippets_.size() > kMaxSnippetCount) {
579 to_delete.insert(
580 to_delete.end(),
581 std::make_move_iterator(snippets_.begin() + kMaxSnippetCount),
582 std::make_move_iterator(snippets_.end()));
583 snippets_.resize(kMaxSnippetCount);
584 }
585
586 // Move expired discarded snippets over into |to_delete| as well. 552 // Move expired discarded snippets over into |to_delete| as well.
587 for (std::unique_ptr<NTPSnippet>& snippet : discarded_snippets_) { 553 for (std::unique_ptr<NTPSnippet>& snippet : discarded_snippets_) {
588 if (snippet->expiry_date() <= expiry) 554 if (snippet->expiry_date() <= expiry)
589 to_delete.emplace_back(std::move(snippet)); 555 to_delete.emplace_back(std::move(snippet));
590 } 556 }
591 Compact(&discarded_snippets_); 557 Compact(&discarded_snippets_);
592 558
593 // Finally, actually delete the removed snippets from the DB. 559 // Finally, actually delete the removed snippets from the DB.
594 database_->Delete(to_delete); 560 database_->Delete(to_delete);
595 561
596 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
597 snippets_.size());
598 if (snippets_.empty() && !discarded_snippets_.empty()) {
599 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
600 discarded_snippets_.size());
601 }
602
603 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
604 NTPSnippetsServiceLoaded());
605
606 // If there are any snippets left, schedule a timer for the next expiry. 562 // If there are any snippets left, schedule a timer for the next expiry.
607 if (snippets_.empty() && discarded_snippets_.empty()) 563 if (snippets_.empty() && discarded_snippets_.empty())
608 return; 564 return;
609 565
610 base::Time next_expiry = base::Time::Max(); 566 base::Time next_expiry = base::Time::Max();
611 for (const auto& snippet : snippets_) { 567 for (const auto& snippet : snippets_) {
612 if (snippet->expiry_date() < next_expiry) 568 if (snippet->expiry_date() < next_expiry)
613 next_expiry = snippet->expiry_date(); 569 next_expiry = snippet->expiry_date();
614 } 570 }
615 for (const auto& snippet : discarded_snippets_) { 571 for (const auto& snippet : discarded_snippets_) {
616 if (snippet->expiry_date() < next_expiry) 572 if (snippet->expiry_date() < next_expiry)
617 next_expiry = snippet->expiry_date(); 573 next_expiry = snippet->expiry_date();
618 } 574 }
619 DCHECK_GT(next_expiry, expiry); 575 DCHECK_GT(next_expiry, expiry);
620 expiry_timer_.Start(FROM_HERE, next_expiry - expiry, 576 expiry_timer_.Start(FROM_HERE, next_expiry - expiry,
621 base::Bind(&NTPSnippetsService::LoadingSnippetsFinished, 577 base::Bind(&NTPSnippetsService::ClearExpiredSnippets,
622 base::Unretained(this))); 578 base::Unretained(this)));
623 } 579 }
624 580
581 void NTPSnippetsService::LoadingSnippetsFinished() {
Bernhard Bauer 2016/06/09 15:21:33 This is now more FetchingSnippetsFinished(). You c
dgn 2016/06/09 16:03:38 Done.
582 DCHECK(ready());
583
584 ClearExpiredSnippets();
585
586 // If there are still more snippets than we want to show, move the extra ones
587 // over into |to_delete| as well.
Marc Treib 2016/06/09 15:52:44 nit: remove "as well"
dgn 2016/06/09 16:03:38 Done.
588 NTPSnippet::PtrVector to_delete;
589 if (snippets_.size() > kMaxSnippetCount) {
590 to_delete.insert(
591 to_delete.end(),
592 std::make_move_iterator(snippets_.begin() + kMaxSnippetCount),
593 std::make_move_iterator(snippets_.end()));
594 snippets_.resize(kMaxSnippetCount);
595 }
596 database_->Delete(to_delete);
597
598 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
599 snippets_.size());
600 if (snippets_.empty() && !discarded_snippets_.empty()) {
601 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
602 discarded_snippets_.size());
603 }
604
605 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
606 NTPSnippetsServiceLoaded());
607 }
608
625 void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) { 609 void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) {
626 if (fetch_snippets) 610 if (fetch_snippets)
627 FetchSnippets(); 611 FetchSnippets();
628 612
629 // If host restrictions are enabled, register for host list updates. 613 // If host restrictions are enabled, register for host list updates.
630 // |suggestions_service_| can be null in tests. 614 // |suggestions_service_| can be null in tests.
631 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { 615 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) {
632 suggestions_service_subscription_ = 616 suggestions_service_subscription_ =
633 suggestions_service_->AddCallback(base::Bind( 617 suggestions_service_->AddCallback(base::Bind(
634 &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this))); 618 &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this)));
(...skipping 18 matching lines...) Expand all
653 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 637 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
654 NTPSnippetsServiceShutdown()); 638 NTPSnippetsServiceShutdown());
655 639
656 expiry_timer_.Stop(); 640 expiry_timer_.Stop();
657 suggestions_service_subscription_.reset(); 641 suggestions_service_subscription_.reset();
658 642
659 if (sync_service_) 643 if (sync_service_)
660 sync_service_observer_.Remove(sync_service_); 644 sync_service_observer_.Remove(sync_service_);
661 } 645 }
662 646
647 void NTPSnippetsService::FinishInitialization() {
648 snippets_fetcher_->SetCallback(
649 base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
650
651 // |sync_service_| can be null in tests or if sync is disabled.
652 // This is a service we want to keep listening to all the time, independently
653 // from the state, since it will allow us to enable or disable the snippets
654 // service.
655 if (sync_service_)
656 sync_service_observer_.Add(sync_service_);
657
658 // Change state after we started loading the snippets. During startup, the
659 // Sync service might not be completely loaded when we initialize this
660 // service. Whether we had snippets in the last season is used to guess if
Bernhard Bauer 2016/06/09 15:21:33 "last session" :)
dgn 2016/06/09 16:03:38 Thanks. The comment was outdated also u_u
661 // we should enable the service or not. See |GetStateForDependenciesStatus|.
662 EnterState(GetStateForDependenciesStatus());
663
664 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
665 NTPSnippetsServiceLoaded());
666
667 // Start a fetch if we don't have any snippets yet, or a fetch was requested
668 // earlier.
669 if (ready() && (snippets_.empty() || fetch_after_load_)) {
670 fetch_after_load_ = false;
671 FetchSnippets();
672 }
673 }
674
663 NTPSnippetsService::State NTPSnippetsService::GetStateForDependenciesStatus() { 675 NTPSnippetsService::State NTPSnippetsService::GetStateForDependenciesStatus() {
664 switch (GetDisabledReason()) { 676 switch (GetDisabledReason()) {
665 case DisabledReason::NONE: 677 case DisabledReason::NONE:
666 return State::READY; 678 return State::READY;
667 679
668 case DisabledReason::HISTORY_SYNC_STATE_UNKNOWN: 680 case DisabledReason::HISTORY_SYNC_STATE_UNKNOWN:
669 // HistorySync is not initialized yet, so we don't know what the actual 681 // HistorySync is not initialized yet, so we don't know what the actual
670 // state is. However, because we retreived the previous snippets from the 682 // state is and we just return the current one. If things change,
671 // database, if we got something, we know that the service was previously 683 // |OnStateChanged| will call this function again to update the state.
672 // enabled, so we just restore that state. If things changed,
673 // |OnStateChanged| will call this function again to fix the state.
674 DVLOG(1) << "Sync configuration incomplete, continuing based on the " 684 DVLOG(1) << "Sync configuration incomplete, continuing based on the "
675 "current state."; 685 "current state.";
676 return snippets_.empty() ? State::DISABLED : State::READY; 686 return state_;
677 687
678 case DisabledReason::EXPLICITLY_DISABLED: 688 case DisabledReason::EXPLICITLY_DISABLED:
679 case DisabledReason::HISTORY_SYNC_DISABLED: 689 case DisabledReason::HISTORY_SYNC_DISABLED:
680 return State::DISABLED; 690 return State::DISABLED;
681 } 691 }
682 692
683 // All cases should be handled by the above switch 693 // All cases should be handled by the above switch
684 NOTREACHED(); 694 NOTREACHED();
685 return State::DISABLED; 695 return State::DISABLED;
686 } 696 }
687 697
688 void NTPSnippetsService::EnterState(State state) { 698 void NTPSnippetsService::EnterState(State state) {
699 if (state == state_)
700 return;
701
689 switch (state) { 702 switch (state) {
690 case State::NOT_INITED: 703 case State::NOT_INITED:
691 // Initial state, it should not be possible to get back there. 704 // Initial state, it should not be possible to get back there.
692 NOTREACHED(); 705 NOTREACHED();
693 return; 706 return;
694 707
695 case State::READY: { 708 case State::READY: {
696 DCHECK(state_ == State::NOT_INITED || state_ == State::READY || 709 DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED);
697 state_ == State::DISABLED);
698 if (state_ == State::READY)
699 return;
700 710
701 // If the service was previously disabled, we will need to start a fetch 711 // If the service was previously disabled, we will need to start a fetch
702 // because otherwise there won't be any. 712 // because otherwise there won't be any.
703 bool fetch_snippets = state_ == State::DISABLED; 713 bool fetch_snippets = state_ == State::DISABLED || fetch_after_load_;
704 DVLOG(1) << "Entering state: READY"; 714 DVLOG(1) << "Entering state: READY";
705 state_ = State::READY; 715 state_ = State::READY;
716 fetch_after_load_ = false;
706 EnterStateEnabled(fetch_snippets); 717 EnterStateEnabled(fetch_snippets);
707 return; 718 return;
708 } 719 }
709 720
710 case State::DISABLED: 721 case State::DISABLED:
711 DCHECK(state_ == State::NOT_INITED || state_ == State::READY || 722 DCHECK(state_ == State::NOT_INITED || state_ == State::READY);
712 state_ == State::DISABLED);
713 if (state_ == State::DISABLED)
714 return;
715 723
716 DVLOG(1) << "Entering state: DISABLED"; 724 DVLOG(1) << "Entering state: DISABLED";
717 state_ = State::DISABLED; 725 state_ = State::DISABLED;
718 EnterStateDisabled(); 726 EnterStateDisabled();
719 return; 727 return;
720 728
721 case State::SHUT_DOWN: 729 case State::SHUT_DOWN:
722 DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED ||
723 state_ == State::READY);
724 DVLOG(1) << "Entering state: SHUT_DOWN"; 730 DVLOG(1) << "Entering state: SHUT_DOWN";
725 state_ = State::SHUT_DOWN; 731 state_ = State::SHUT_DOWN;
726 EnterStateShutdown(); 732 EnterStateShutdown();
727 return; 733 return;
728 } 734 }
729 } 735 }
730 736
731 void NTPSnippetsService::ClearDeprecatedPrefs() { 737 void NTPSnippetsService::ClearDeprecatedPrefs() {
732 pref_service_->ClearPref(prefs::kDeprecatedSnippets); 738 pref_service_->ClearPref(prefs::kDeprecatedSnippets);
733 pref_service_->ClearPref(prefs::kDeprecatedDiscardedSnippets); 739 pref_service_->ClearPref(prefs::kDeprecatedDiscardedSnippets);
734 } 740 }
735 741
736 } // namespace ntp_snippets 742 } // namespace ntp_snippets
OLDNEW
« no previous file with comments | « components/ntp_snippets/ntp_snippets_service.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698