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

Unified Diff: components/ntp_snippets/ntp_snippets_service.cc

Issue 1987333003: [NTP Snippets] Persist snippets in a LevelDB instead of prefs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix test memleaks Created 4 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: components/ntp_snippets/ntp_snippets_service.cc
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc
index 23319e5aa130941f4cf4fc672fec7ffded1c1c08..60a87b6895d1e8f6ef773ca95d6fe22c8ad1912c 100644
--- a/components/ntp_snippets/ntp_snippets_service.cc
+++ b/components/ntp_snippets/ntp_snippets_service.cc
@@ -21,6 +21,7 @@
#include "base/values.h"
#include "components/image_fetcher/image_fetcher.h"
#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/ntp_snippets/ntp_snippets_database.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/ntp_snippets/switches.h"
#include "components/prefs/pref_registry_simple.h"
@@ -157,16 +158,6 @@ std::set<std::string> GetSuggestionsHostsImpl(
return hosts;
}
-std::unique_ptr<base::ListValue> SnippetsToListValue(
- const NTPSnippet::PtrVector& snippets) {
- std::unique_ptr<base::ListValue> list(new base::ListValue);
- for (const auto& snippet : snippets) {
- std::unique_ptr<base::DictionaryValue> dict = snippet->ToDictionary();
- list->Append(std::move(dict));
- }
- return list;
-}
-
void InsertAllIDs(const NTPSnippet::PtrVector& snippets,
std::set<std::string>* ids) {
for (const std::unique_ptr<NTPSnippet>& snippet : snippets) {
@@ -176,6 +167,14 @@ void InsertAllIDs(const NTPSnippet::PtrVector& snippets,
}
}
+void Compact(NTPSnippet::PtrVector* snippets) {
+ snippets->erase(
+ std::remove_if(
+ snippets->begin(), snippets->end(),
+ [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }),
+ snippets->end());
+}
+
} // namespace
NTPSnippetsService::NTPSnippetsService(
@@ -183,22 +182,23 @@ NTPSnippetsService::NTPSnippetsService(
PrefService* pref_service,
sync_driver::SyncService* sync_service,
SuggestionsService* suggestions_service,
- scoped_refptr<base::SequencedTaskRunner> file_task_runner,
const std::string& application_language_code,
NTPSnippetsScheduler* scheduler,
std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
- std::unique_ptr<ImageFetcher> image_fetcher)
+ std::unique_ptr<ImageFetcher> image_fetcher,
+ std::unique_ptr<NTPSnippetsDatabase> database)
: state_(State::INITED),
enabled_(enabled),
pref_service_(pref_service),
sync_service_(sync_service),
sync_service_observer_(this),
suggestions_service_(suggestions_service),
- file_task_runner_(file_task_runner),
application_language_code_(application_language_code),
scheduler_(scheduler),
snippets_fetcher_(std::move(snippets_fetcher)),
- image_fetcher_(std::move(image_fetcher)) {
+ image_fetcher_(std::move(image_fetcher)),
+ database_(std::move(database)),
+ fetch_after_load_(false) {
snippets_fetcher_->SetCallback(base::Bind(
&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
@@ -207,23 +207,13 @@ NTPSnippetsService::NTPSnippetsService(
sync_service_observer_.Add(sync_service_);
if (enabled_) {
- // |suggestions_service_| can be null in tests.
- if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) {
- suggestions_service_subscription_ = suggestions_service_->AddCallback(
- base::Bind(&NTPSnippetsService::OnSuggestionsChanged,
- base::Unretained(this)));
- }
-
- // Get any existing snippets immediately from prefs.
- LoadDiscardedSnippetsFromPrefs();
- LoadSnippetsFromPrefs();
-
- // If we don't have any snippets yet, start a fetch.
- if (snippets_.empty())
- FetchSnippets();
+ database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
+ base::Unretained(this)));
}
RescheduleFetching();
+
+ ClearDeprecatedPrefs();
}
NTPSnippetsService::~NTPSnippetsService() {
@@ -232,27 +222,33 @@ NTPSnippetsService::~NTPSnippetsService() {
// static
void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
- registry->RegisterListPref(prefs::kSnippets);
- registry->RegisterListPref(prefs::kDiscardedSnippets);
+ registry->RegisterListPref(prefs::kDeprecatedSnippets);
+ registry->RegisterListPref(prefs::kDeprecatedDiscardedSnippets);
registry->RegisterListPref(prefs::kSnippetHosts);
}
void NTPSnippetsService::Shutdown() {
- DCHECK(state_ == State::INITED);
+ DCHECK(state_ == State::INITED || state_ == State::LOADED);
state_ = State::SHUT_DOWN;
FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
NTPSnippetsServiceShutdown());
+ expiry_timer_.Stop();
suggestions_service_subscription_.reset();
enabled_ = false;
}
void NTPSnippetsService::FetchSnippets() {
- FetchSnippetsFromHosts(GetSuggestionsHosts());
+ if (loaded())
+ FetchSnippetsFromHosts(GetSuggestionsHosts());
+ else
+ fetch_after_load_ = true;
}
void NTPSnippetsService::FetchSnippetsFromHosts(
const std::set<std::string>& hosts) {
+ if (!loaded())
+ return;
snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_,
kMaxSnippetCount);
}
@@ -293,9 +289,11 @@ void NTPSnippetsService::FetchSnippetImage(
}
void NTPSnippetsService::ClearSnippets() {
- snippets_.clear();
+ if (!loaded())
+ return;
- StoreSnippetsToPrefs();
+ database_->Delete(snippets_);
+ snippets_.clear();
FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
NTPSnippetsServiceLoaded());
@@ -306,12 +304,15 @@ std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const {
if (!suggestions_service_)
return std::set<std::string>();
- // TODO(treib) this should just call GetSnippetHostsFromPrefs
+ // TODO(treib): This should just call GetSnippetHostsFromPrefs.
return GetSuggestionsHostsImpl(
suggestions_service_->GetSuggestionsDataFromCache());
}
bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) {
+ if (!loaded())
+ return false;
+
auto it =
std::find_if(snippets_.begin(), snippets_.end(),
[&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
@@ -319,18 +320,26 @@ bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) {
});
if (it == snippets_.end())
return false;
+
+ (*it)->set_discarded(true);
+
+ database_->Save(**it);
+
discarded_snippets_.push_back(std::move(*it));
snippets_.erase(it);
- StoreDiscardedSnippetsToPrefs();
- StoreSnippetsToPrefs();
+
FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
NTPSnippetsServiceLoaded());
return true;
}
void NTPSnippetsService::ClearDiscardedSnippets() {
+ if (!loaded())
+ return;
+
+ database_->Delete(discarded_snippets_);
discarded_snippets_.clear();
- StoreDiscardedSnippetsToPrefs();
+
FetchSnippets();
}
@@ -365,8 +374,47 @@ void NTPSnippetsService::OnStateChanged() {
FetchSnippets();
}
+void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
+ DCHECK(state_ == State::INITED || state_ == State::SHUT_DOWN);
+ if (state_ == State::SHUT_DOWN)
+ return;
+ state_ = State::LOADED;
+
+ DCHECK(snippets_.empty());
+ DCHECK(discarded_snippets_.empty());
+ for (std::unique_ptr<NTPSnippet>& snippet : snippets) {
+ if (snippet->is_discarded())
+ discarded_snippets_.emplace_back(std::move(snippet));
+ else
+ snippets_.emplace_back(std::move(snippet));
+ }
+ std::sort(snippets_.begin(), snippets_.end(),
+ [](const std::unique_ptr<NTPSnippet>& lhs,
+ const std::unique_ptr<NTPSnippet>& rhs) {
+ return lhs->score() > rhs->score();
+ });
+ LoadingSnippetsFinished();
+
+ // If host restrictions are enabled, register for host list updates.
+ // |suggestions_service_| can be null in tests.
+ if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) {
+ suggestions_service_subscription_ =
+ suggestions_service_->AddCallback(base::Bind(
+ &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this)));
+ }
+
+ // Start a fetch if we don't have any snippets yet, or a fetch was requested
+ // earlier.
+ if (snippets_.empty() || fetch_after_load_) {
+ fetch_after_load_ = false;
+ FetchSnippets();
+ }
+}
+
void NTPSnippetsService::OnSuggestionsChanged(
const SuggestionsProfile& suggestions) {
+ DCHECK(loaded());
+
std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions);
if (hosts == GetSnippetHostsFromPrefs())
return;
@@ -374,14 +422,16 @@ void NTPSnippetsService::OnSuggestionsChanged(
// Remove existing snippets that aren't in the suggestions anymore.
// TODO(treib,maybelle): If there is another source with an allowed host,
// then we should fall back to that.
- snippets_.erase(
- std::remove_if(snippets_.begin(), snippets_.end(),
- [&hosts](const std::unique_ptr<NTPSnippet>& snippet) {
- return !hosts.count(snippet->best_source().url.host());
- }),
- snippets_.end());
-
- StoreSnippetsToPrefs();
+ // First, move them over into |to_delete|.
+ NTPSnippet::PtrVector to_delete;
+ for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
+ if (!hosts.count(snippet->best_source().url.host()))
+ to_delete.emplace_back(std::move(snippet));
+ }
+ Compact(&snippets_);
+ // Then delete the removed snippets from the database.
+ database_->Delete(to_delete);
+
StoreSnippetHostsToPrefs(hosts);
FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
@@ -392,6 +442,9 @@ void NTPSnippetsService::OnSuggestionsChanged(
void NTPSnippetsService::OnFetchFinished(
NTPSnippetsFetcher::OptionalSnippets snippets) {
+ if (!loaded())
+ return;
+
if (snippets) {
// Sparse histogram used because the number of snippets is small (bound by
// kMaxSnippetCount).
@@ -404,6 +457,8 @@ void NTPSnippetsService::OnFetchFinished(
}
void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) {
+ DCHECK(loaded());
+
// Remove new snippets that we already have, or that have been discarded.
std::set<std::string> old_snippet_ids;
InsertAllIDs(discarded_snippets_, &old_snippet_ids);
@@ -454,37 +509,16 @@ void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) {
num_snippets_discarded);
}
}
+
+ // Save the new snippets to the DB.
+ database_->Save(new_snippets);
+
// Insert the new snippets at the front.
snippets_.insert(snippets_.begin(),
std::make_move_iterator(new_snippets.begin()),
std::make_move_iterator(new_snippets.end()));
}
-void NTPSnippetsService::LoadSnippetsFromPrefs() {
- NTPSnippet::PtrVector prefs_snippets;
- bool success = NTPSnippet::AddFromListValue(
- *pref_service_->GetList(prefs::kSnippets), &prefs_snippets);
- DCHECK(success) << "Failed to parse snippets from prefs";
- MergeSnippets(std::move(prefs_snippets));
- LoadingSnippetsFinished();
-}
-
-void NTPSnippetsService::StoreSnippetsToPrefs() {
- pref_service_->Set(prefs::kSnippets, *SnippetsToListValue(snippets_));
-}
-
-void NTPSnippetsService::LoadDiscardedSnippetsFromPrefs() {
- discarded_snippets_.clear();
- bool success = NTPSnippet::AddFromListValue(
- *pref_service_->GetList(prefs::kDiscardedSnippets), &discarded_snippets_);
- DCHECK(success) << "Failed to parse discarded snippets from prefs";
-}
-
-void NTPSnippetsService::StoreDiscardedSnippetsToPrefs() {
- pref_service_->Set(prefs::kDiscardedSnippets,
- *SnippetsToListValue(discarded_snippets_));
-}
-
std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const {
std::set<std::string> hosts;
const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts);
@@ -506,30 +540,38 @@ void NTPSnippetsService::StoreSnippetHostsToPrefs(
}
void NTPSnippetsService::LoadingSnippetsFinished() {
+ DCHECK(loaded());
+
// Remove expired snippets.
base::Time expiry = base::Time::Now();
- snippets_.erase(
- std::remove_if(snippets_.begin(), snippets_.end(),
- [&expiry](const std::unique_ptr<NTPSnippet>& snippet) {
- return snippet->expiry_date() <= expiry;
- }),
- snippets_.end());
-
- // If there are more snippets now than we want to show, drop the extra ones
- // from the end of the list.
- if (snippets_.size() > kMaxSnippetCount)
+ // Move expired snippets over into |to_delete|.
+ NTPSnippet::PtrVector to_delete;
+ for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
+ if (snippet->expiry_date() <= expiry)
+ to_delete.emplace_back(std::move(snippet));
+ }
+ Compact(&snippets_);
+
+ // If there are still more snippets than we want to show, move the extra ones
+ // over into |to_delete| as well.
+ if (snippets_.size() > kMaxSnippetCount) {
+ to_delete.insert(
+ to_delete.end(),
+ std::make_move_iterator(snippets_.begin() + kMaxSnippetCount),
+ std::make_move_iterator(snippets_.end()));
snippets_.resize(kMaxSnippetCount);
+ }
- StoreSnippetsToPrefs();
+ // Move expired discarded snippets over into |to_delete| as well.
+ for (std::unique_ptr<NTPSnippet>& snippet : discarded_snippets_) {
+ if (snippet->expiry_date() <= expiry)
+ to_delete.emplace_back(std::move(snippet));
+ }
+ Compact(&discarded_snippets_);
- discarded_snippets_.erase(
- std::remove_if(discarded_snippets_.begin(), discarded_snippets_.end(),
- [&expiry](const std::unique_ptr<NTPSnippet>& snippet) {
- return snippet->expiry_date() <= expiry;
- }),
- discarded_snippets_.end());
- StoreDiscardedSnippetsToPrefs();
+ // Finally, actually delete the removed snippets from the DB.
+ database_->Delete(to_delete);
UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
snippets_.size());
@@ -569,4 +611,9 @@ bool NTPSnippetsService::IsSyncStateIncompatible() {
syncer::HISTORY_DELETE_DIRECTIVES);
}
+void NTPSnippetsService::ClearDeprecatedPrefs() {
+ pref_service_->ClearPref(prefs::kDeprecatedSnippets);
+ pref_service_->ClearPref(prefs::kDeprecatedDiscardedSnippets);
+}
+
} // namespace ntp_snippets
« no previous file with comments | « components/ntp_snippets/ntp_snippets_service.h ('k') | components/ntp_snippets/ntp_snippets_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698