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

Side by Side 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, 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
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
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h" 13 #include "base/files/file_util.h"
14 #include "base/location.h" 14 #include "base/location.h"
15 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
16 #include "base/metrics/sparse_histogram.h" 16 #include "base/metrics/sparse_histogram.h"
17 #include "base/path_service.h" 17 #include "base/path_service.h"
18 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
19 #include "base/task_runner_util.h" 19 #include "base/task_runner_util.h"
20 #include "base/time/time.h" 20 #include "base/time/time.h"
21 #include "base/values.h" 21 #include "base/values.h"
22 #include "components/image_fetcher/image_fetcher.h" 22 #include "components/image_fetcher/image_fetcher.h"
23 #include "components/ntp_snippets/ntp_snippets_constants.h" 23 #include "components/ntp_snippets/ntp_snippets_constants.h"
24 #include "components/ntp_snippets/ntp_snippets_database.h"
24 #include "components/ntp_snippets/pref_names.h" 25 #include "components/ntp_snippets/pref_names.h"
25 #include "components/ntp_snippets/switches.h" 26 #include "components/ntp_snippets/switches.h"
26 #include "components/prefs/pref_registry_simple.h" 27 #include "components/prefs/pref_registry_simple.h"
27 #include "components/prefs/pref_service.h" 28 #include "components/prefs/pref_service.h"
28 #include "components/suggestions/proto/suggestions.pb.h" 29 #include "components/suggestions/proto/suggestions.pb.h"
29 #include "components/sync_driver/sync_service.h" 30 #include "components/sync_driver/sync_service.h"
30 #include "components/variations/variations_associated_data.h" 31 #include "components/variations/variations_associated_data.h"
31 #include "ui/gfx/image/image.h" 32 #include "ui/gfx/image/image.h"
32 33
33 using image_fetcher::ImageFetcher; 34 using image_fetcher::ImageFetcher;
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 std::set<std::string> hosts; 151 std::set<std::string> hosts;
151 for (int i = 0; i < suggestions.suggestions_size(); ++i) { 152 for (int i = 0; i < suggestions.suggestions_size(); ++i) {
152 const ChromeSuggestion& suggestion = suggestions.suggestions(i); 153 const ChromeSuggestion& suggestion = suggestions.suggestions(i);
153 GURL url(suggestion.url()); 154 GURL url(suggestion.url());
154 if (url.is_valid()) 155 if (url.is_valid())
155 hosts.insert(url.host()); 156 hosts.insert(url.host());
156 } 157 }
157 return hosts; 158 return hosts;
158 } 159 }
159 160
160 std::unique_ptr<base::ListValue> SnippetsToListValue(
161 const NTPSnippet::PtrVector& snippets) {
162 std::unique_ptr<base::ListValue> list(new base::ListValue);
163 for (const auto& snippet : snippets) {
164 std::unique_ptr<base::DictionaryValue> dict = snippet->ToDictionary();
165 list->Append(std::move(dict));
166 }
167 return list;
168 }
169
170 void InsertAllIDs(const NTPSnippet::PtrVector& snippets, 161 void InsertAllIDs(const NTPSnippet::PtrVector& snippets,
171 std::set<std::string>* ids) { 162 std::set<std::string>* ids) {
172 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) { 163 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) {
173 ids->insert(snippet->id()); 164 ids->insert(snippet->id());
174 for (const SnippetSource& source : snippet->sources()) 165 for (const SnippetSource& source : snippet->sources())
175 ids->insert(source.url.spec()); 166 ids->insert(source.url.spec());
176 } 167 }
177 } 168 }
178 169
170 void Compact(NTPSnippet::PtrVector* snippets) {
171 snippets->erase(
172 std::remove_if(
173 snippets->begin(), snippets->end(),
174 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }),
175 snippets->end());
176 }
177
179 } // namespace 178 } // namespace
180 179
181 NTPSnippetsService::NTPSnippetsService( 180 NTPSnippetsService::NTPSnippetsService(
182 bool enabled, 181 bool enabled,
183 PrefService* pref_service, 182 PrefService* pref_service,
184 sync_driver::SyncService* sync_service, 183 sync_driver::SyncService* sync_service,
185 SuggestionsService* suggestions_service, 184 SuggestionsService* suggestions_service,
186 scoped_refptr<base::SequencedTaskRunner> file_task_runner,
187 const std::string& application_language_code, 185 const std::string& application_language_code,
188 NTPSnippetsScheduler* scheduler, 186 NTPSnippetsScheduler* scheduler,
189 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, 187 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
190 std::unique_ptr<ImageFetcher> image_fetcher) 188 std::unique_ptr<ImageFetcher> image_fetcher,
189 std::unique_ptr<NTPSnippetsDatabase> database)
191 : state_(State::INITED), 190 : state_(State::INITED),
192 enabled_(enabled), 191 enabled_(enabled),
193 pref_service_(pref_service), 192 pref_service_(pref_service),
194 sync_service_(sync_service), 193 sync_service_(sync_service),
195 sync_service_observer_(this), 194 sync_service_observer_(this),
196 suggestions_service_(suggestions_service), 195 suggestions_service_(suggestions_service),
197 file_task_runner_(file_task_runner),
198 application_language_code_(application_language_code), 196 application_language_code_(application_language_code),
199 scheduler_(scheduler), 197 scheduler_(scheduler),
200 snippets_fetcher_(std::move(snippets_fetcher)), 198 snippets_fetcher_(std::move(snippets_fetcher)),
201 image_fetcher_(std::move(image_fetcher)) { 199 image_fetcher_(std::move(image_fetcher)),
200 database_(std::move(database)),
201 fetch_after_load_(false) {
202 snippets_fetcher_->SetCallback(base::Bind( 202 snippets_fetcher_->SetCallback(base::Bind(
203 &NTPSnippetsService::OnFetchFinished, base::Unretained(this))); 203 &NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
204 204
205 // |sync_service_| can be null in tests or if sync is disabled. 205 // |sync_service_| can be null in tests or if sync is disabled.
206 if (sync_service_) 206 if (sync_service_)
207 sync_service_observer_.Add(sync_service_); 207 sync_service_observer_.Add(sync_service_);
208 208
209 if (enabled_) { 209 if (enabled_) {
210 // |suggestions_service_| can be null in tests. 210 database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
211 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { 211 base::Unretained(this)));
212 suggestions_service_subscription_ = suggestions_service_->AddCallback(
213 base::Bind(&NTPSnippetsService::OnSuggestionsChanged,
214 base::Unretained(this)));
215 }
216
217 // Get any existing snippets immediately from prefs.
218 LoadDiscardedSnippetsFromPrefs();
219 LoadSnippetsFromPrefs();
220
221 // If we don't have any snippets yet, start a fetch.
222 if (snippets_.empty())
223 FetchSnippets();
224 } 212 }
225 213
226 RescheduleFetching(); 214 RescheduleFetching();
215
216 ClearDeprecatedPrefs();
227 } 217 }
228 218
229 NTPSnippetsService::~NTPSnippetsService() { 219 NTPSnippetsService::~NTPSnippetsService() {
230 DCHECK(state_ == State::SHUT_DOWN); 220 DCHECK(state_ == State::SHUT_DOWN);
231 } 221 }
232 222
233 // static 223 // static
234 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { 224 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
235 registry->RegisterListPref(prefs::kSnippets); 225 registry->RegisterListPref(prefs::kDeprecatedSnippets);
236 registry->RegisterListPref(prefs::kDiscardedSnippets); 226 registry->RegisterListPref(prefs::kDeprecatedDiscardedSnippets);
237 registry->RegisterListPref(prefs::kSnippetHosts); 227 registry->RegisterListPref(prefs::kSnippetHosts);
238 } 228 }
239 229
240 void NTPSnippetsService::Shutdown() { 230 void NTPSnippetsService::Shutdown() {
241 DCHECK(state_ == State::INITED); 231 DCHECK(state_ == State::INITED || state_ == State::LOADED);
242 state_ = State::SHUT_DOWN; 232 state_ = State::SHUT_DOWN;
243 233
244 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 234 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
245 NTPSnippetsServiceShutdown()); 235 NTPSnippetsServiceShutdown());
236 expiry_timer_.Stop();
246 suggestions_service_subscription_.reset(); 237 suggestions_service_subscription_.reset();
247 enabled_ = false; 238 enabled_ = false;
248 } 239 }
249 240
250 void NTPSnippetsService::FetchSnippets() { 241 void NTPSnippetsService::FetchSnippets() {
251 FetchSnippetsFromHosts(GetSuggestionsHosts()); 242 if (loaded())
243 FetchSnippetsFromHosts(GetSuggestionsHosts());
244 else
245 fetch_after_load_ = true;
252 } 246 }
253 247
254 void NTPSnippetsService::FetchSnippetsFromHosts( 248 void NTPSnippetsService::FetchSnippetsFromHosts(
255 const std::set<std::string>& hosts) { 249 const std::set<std::string>& hosts) {
250 if (!loaded())
251 return;
256 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, 252 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_,
257 kMaxSnippetCount); 253 kMaxSnippetCount);
258 } 254 }
259 255
260 void NTPSnippetsService::RescheduleFetching() { 256 void NTPSnippetsService::RescheduleFetching() {
261 // The scheduler only exists on Android so far, it's null on other platforms. 257 // The scheduler only exists on Android so far, it's null on other platforms.
262 if (!scheduler_) 258 if (!scheduler_)
263 return; 259 return;
264 260
265 if (enabled_) { 261 if (enabled_) {
(...skipping 20 matching lines...) Expand all
286 return; 282 return;
287 } 283 }
288 284
289 const NTPSnippet& snippet = *it->get(); 285 const NTPSnippet& snippet = *it->get();
290 image_fetcher_->StartOrQueueNetworkRequest( 286 image_fetcher_->StartOrQueueNetworkRequest(
291 snippet.id(), snippet.salient_image_url(), callback); 287 snippet.id(), snippet.salient_image_url(), callback);
292 // TODO(treib): Cache/persist the snippet image. 288 // TODO(treib): Cache/persist the snippet image.
293 } 289 }
294 290
295 void NTPSnippetsService::ClearSnippets() { 291 void NTPSnippetsService::ClearSnippets() {
292 if (!loaded())
293 return;
294
295 database_->Delete(snippets_);
296 snippets_.clear(); 296 snippets_.clear();
297 297
298 StoreSnippetsToPrefs();
299
300 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 298 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
301 NTPSnippetsServiceLoaded()); 299 NTPSnippetsServiceLoaded());
302 } 300 }
303 301
304 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { 302 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const {
305 // |suggestions_service_| can be null in tests. 303 // |suggestions_service_| can be null in tests.
306 if (!suggestions_service_) 304 if (!suggestions_service_)
307 return std::set<std::string>(); 305 return std::set<std::string>();
308 306
309 // TODO(treib) this should just call GetSnippetHostsFromPrefs 307 // TODO(treib): This should just call GetSnippetHostsFromPrefs.
310 return GetSuggestionsHostsImpl( 308 return GetSuggestionsHostsImpl(
311 suggestions_service_->GetSuggestionsDataFromCache()); 309 suggestions_service_->GetSuggestionsDataFromCache());
312 } 310 }
313 311
314 bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) { 312 bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) {
313 if (!loaded())
314 return false;
315
315 auto it = 316 auto it =
316 std::find_if(snippets_.begin(), snippets_.end(), 317 std::find_if(snippets_.begin(), snippets_.end(),
317 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { 318 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
318 return snippet->id() == snippet_id; 319 return snippet->id() == snippet_id;
319 }); 320 });
320 if (it == snippets_.end()) 321 if (it == snippets_.end())
321 return false; 322 return false;
323
324 (*it)->set_discarded(true);
325
326 database_->Save(**it);
327
322 discarded_snippets_.push_back(std::move(*it)); 328 discarded_snippets_.push_back(std::move(*it));
323 snippets_.erase(it); 329 snippets_.erase(it);
324 StoreDiscardedSnippetsToPrefs(); 330
325 StoreSnippetsToPrefs();
326 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 331 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
327 NTPSnippetsServiceLoaded()); 332 NTPSnippetsServiceLoaded());
328 return true; 333 return true;
329 } 334 }
330 335
331 void NTPSnippetsService::ClearDiscardedSnippets() { 336 void NTPSnippetsService::ClearDiscardedSnippets() {
337 if (!loaded())
338 return;
339
340 database_->Delete(discarded_snippets_);
332 discarded_snippets_.clear(); 341 discarded_snippets_.clear();
333 StoreDiscardedSnippetsToPrefs(); 342
334 FetchSnippets(); 343 FetchSnippets();
335 } 344 }
336 345
337 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) { 346 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) {
338 observers_.AddObserver(observer); 347 observers_.AddObserver(observer);
339 } 348 }
340 349
341 void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) { 350 void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) {
342 observers_.RemoveObserver(observer); 351 observers_.RemoveObserver(observer);
343 } 352 }
(...skipping 14 matching lines...) Expand all
358 NTPSnippetsServiceDisabled()); 367 NTPSnippetsServiceDisabled());
359 return; 368 return;
360 } 369 }
361 370
362 // TODO(dgn): When the data sources change, we may want to not fetch here, 371 // TODO(dgn): When the data sources change, we may want to not fetch here,
363 // as we will get notified of changes from the snippet sources as well, and 372 // as we will get notified of changes from the snippet sources as well, and
364 // start multiple fetches. 373 // start multiple fetches.
365 FetchSnippets(); 374 FetchSnippets();
366 } 375 }
367 376
377 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
378 DCHECK(state_ == State::INITED || state_ == State::SHUT_DOWN);
379 if (state_ == State::SHUT_DOWN)
380 return;
381 state_ = State::LOADED;
382
383 DCHECK(snippets_.empty());
384 DCHECK(discarded_snippets_.empty());
385 for (std::unique_ptr<NTPSnippet>& snippet : snippets) {
386 if (snippet->is_discarded())
387 discarded_snippets_.emplace_back(std::move(snippet));
388 else
389 snippets_.emplace_back(std::move(snippet));
390 }
391 std::sort(snippets_.begin(), snippets_.end(),
392 [](const std::unique_ptr<NTPSnippet>& lhs,
393 const std::unique_ptr<NTPSnippet>& rhs) {
394 return lhs->score() > rhs->score();
395 });
396 LoadingSnippetsFinished();
397
398 // If host restrictions are enabled, register for host list updates.
399 // |suggestions_service_| can be null in tests.
400 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) {
401 suggestions_service_subscription_ =
402 suggestions_service_->AddCallback(base::Bind(
403 &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this)));
404 }
405
406 // Start a fetch if we don't have any snippets yet, or a fetch was requested
407 // earlier.
408 if (snippets_.empty() || fetch_after_load_) {
409 fetch_after_load_ = false;
410 FetchSnippets();
411 }
412 }
413
368 void NTPSnippetsService::OnSuggestionsChanged( 414 void NTPSnippetsService::OnSuggestionsChanged(
369 const SuggestionsProfile& suggestions) { 415 const SuggestionsProfile& suggestions) {
416 DCHECK(loaded());
417
370 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); 418 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions);
371 if (hosts == GetSnippetHostsFromPrefs()) 419 if (hosts == GetSnippetHostsFromPrefs())
372 return; 420 return;
373 421
374 // Remove existing snippets that aren't in the suggestions anymore. 422 // Remove existing snippets that aren't in the suggestions anymore.
375 // TODO(treib,maybelle): If there is another source with an allowed host, 423 // TODO(treib,maybelle): If there is another source with an allowed host,
376 // then we should fall back to that. 424 // then we should fall back to that.
377 snippets_.erase( 425 // First, move them over into |to_delete|.
378 std::remove_if(snippets_.begin(), snippets_.end(), 426 NTPSnippet::PtrVector to_delete;
379 [&hosts](const std::unique_ptr<NTPSnippet>& snippet) { 427 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
380 return !hosts.count(snippet->best_source().url.host()); 428 if (!hosts.count(snippet->best_source().url.host()))
381 }), 429 to_delete.emplace_back(std::move(snippet));
382 snippets_.end()); 430 }
431 Compact(&snippets_);
432 // Then delete the removed snippets from the database.
433 database_->Delete(to_delete);
383 434
384 StoreSnippetsToPrefs();
385 StoreSnippetHostsToPrefs(hosts); 435 StoreSnippetHostsToPrefs(hosts);
386 436
387 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 437 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
388 NTPSnippetsServiceLoaded()); 438 NTPSnippetsServiceLoaded());
389 439
390 FetchSnippetsFromHosts(hosts); 440 FetchSnippetsFromHosts(hosts);
391 } 441 }
392 442
393 void NTPSnippetsService::OnFetchFinished( 443 void NTPSnippetsService::OnFetchFinished(
394 NTPSnippetsFetcher::OptionalSnippets snippets) { 444 NTPSnippetsFetcher::OptionalSnippets snippets) {
445 if (!loaded())
446 return;
447
395 if (snippets) { 448 if (snippets) {
396 // Sparse histogram used because the number of snippets is small (bound by 449 // Sparse histogram used because the number of snippets is small (bound by
397 // kMaxSnippetCount). 450 // kMaxSnippetCount).
398 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); 451 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount));
399 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", 452 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched",
400 snippets->size()); 453 snippets->size());
401 MergeSnippets(std::move(*snippets)); 454 MergeSnippets(std::move(*snippets));
402 } 455 }
403 LoadingSnippetsFinished(); 456 LoadingSnippetsFinished();
404 } 457 }
405 458
406 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { 459 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) {
460 DCHECK(loaded());
461
407 // Remove new snippets that we already have, or that have been discarded. 462 // Remove new snippets that we already have, or that have been discarded.
408 std::set<std::string> old_snippet_ids; 463 std::set<std::string> old_snippet_ids;
409 InsertAllIDs(discarded_snippets_, &old_snippet_ids); 464 InsertAllIDs(discarded_snippets_, &old_snippet_ids);
410 InsertAllIDs(snippets_, &old_snippet_ids); 465 InsertAllIDs(snippets_, &old_snippet_ids);
411 new_snippets.erase( 466 new_snippets.erase(
412 std::remove_if( 467 std::remove_if(
413 new_snippets.begin(), new_snippets.end(), 468 new_snippets.begin(), new_snippets.end(),
414 [&old_snippet_ids](const std::unique_ptr<NTPSnippet>& snippet) { 469 [&old_snippet_ids](const std::unique_ptr<NTPSnippet>& snippet) {
415 if (old_snippet_ids.count(snippet->id())) 470 if (old_snippet_ids.count(snippet->id()))
416 return true; 471 return true;
(...skipping 30 matching lines...) Expand all
447 }), 502 }),
448 new_snippets.end()); 503 new_snippets.end());
449 int num_snippets_discarded = num_new_snippets - new_snippets.size(); 504 int num_snippets_discarded = num_new_snippets - new_snippets.size();
450 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch", 505 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
451 num_snippets_discarded > 0); 506 num_snippets_discarded > 0);
452 if (num_snippets_discarded > 0) { 507 if (num_snippets_discarded > 0) {
453 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets", 508 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
454 num_snippets_discarded); 509 num_snippets_discarded);
455 } 510 }
456 } 511 }
512
513 // Save the new snippets to the DB.
514 database_->Save(new_snippets);
515
457 // Insert the new snippets at the front. 516 // Insert the new snippets at the front.
458 snippets_.insert(snippets_.begin(), 517 snippets_.insert(snippets_.begin(),
459 std::make_move_iterator(new_snippets.begin()), 518 std::make_move_iterator(new_snippets.begin()),
460 std::make_move_iterator(new_snippets.end())); 519 std::make_move_iterator(new_snippets.end()));
461 } 520 }
462 521
463 void NTPSnippetsService::LoadSnippetsFromPrefs() {
464 NTPSnippet::PtrVector prefs_snippets;
465 bool success = NTPSnippet::AddFromListValue(
466 *pref_service_->GetList(prefs::kSnippets), &prefs_snippets);
467 DCHECK(success) << "Failed to parse snippets from prefs";
468 MergeSnippets(std::move(prefs_snippets));
469 LoadingSnippetsFinished();
470 }
471
472 void NTPSnippetsService::StoreSnippetsToPrefs() {
473 pref_service_->Set(prefs::kSnippets, *SnippetsToListValue(snippets_));
474 }
475
476 void NTPSnippetsService::LoadDiscardedSnippetsFromPrefs() {
477 discarded_snippets_.clear();
478 bool success = NTPSnippet::AddFromListValue(
479 *pref_service_->GetList(prefs::kDiscardedSnippets), &discarded_snippets_);
480 DCHECK(success) << "Failed to parse discarded snippets from prefs";
481 }
482
483 void NTPSnippetsService::StoreDiscardedSnippetsToPrefs() {
484 pref_service_->Set(prefs::kDiscardedSnippets,
485 *SnippetsToListValue(discarded_snippets_));
486 }
487
488 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const { 522 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const {
489 std::set<std::string> hosts; 523 std::set<std::string> hosts;
490 const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts); 524 const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts);
491 for (const auto& value : *list) { 525 for (const auto& value : *list) {
492 std::string str; 526 std::string str;
493 bool success = value->GetAsString(&str); 527 bool success = value->GetAsString(&str);
494 DCHECK(success) << "Failed to parse snippet host from prefs"; 528 DCHECK(success) << "Failed to parse snippet host from prefs";
495 hosts.insert(std::move(str)); 529 hosts.insert(std::move(str));
496 } 530 }
497 return hosts; 531 return hosts;
498 } 532 }
499 533
500 void NTPSnippetsService::StoreSnippetHostsToPrefs( 534 void NTPSnippetsService::StoreSnippetHostsToPrefs(
501 const std::set<std::string>& hosts) { 535 const std::set<std::string>& hosts) {
502 base::ListValue list; 536 base::ListValue list;
503 for (const std::string& host : hosts) 537 for (const std::string& host : hosts)
504 list.AppendString(host); 538 list.AppendString(host);
505 pref_service_->Set(prefs::kSnippetHosts, list); 539 pref_service_->Set(prefs::kSnippetHosts, list);
506 } 540 }
507 541
508 void NTPSnippetsService::LoadingSnippetsFinished() { 542 void NTPSnippetsService::LoadingSnippetsFinished() {
543 DCHECK(loaded());
544
509 // Remove expired snippets. 545 // Remove expired snippets.
510 base::Time expiry = base::Time::Now(); 546 base::Time expiry = base::Time::Now();
511 547
512 snippets_.erase( 548 // Move expired snippets over into |to_delete|.
513 std::remove_if(snippets_.begin(), snippets_.end(), 549 NTPSnippet::PtrVector to_delete;
514 [&expiry](const std::unique_ptr<NTPSnippet>& snippet) { 550 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
515 return snippet->expiry_date() <= expiry; 551 if (snippet->expiry_date() <= expiry)
516 }), 552 to_delete.emplace_back(std::move(snippet));
517 snippets_.end()); 553 }
554 Compact(&snippets_);
518 555
519 // If there are more snippets now than we want to show, drop the extra ones 556 // If there are still more snippets than we want to show, move the extra ones
520 // from the end of the list. 557 // over into |to_delete| as well.
521 if (snippets_.size() > kMaxSnippetCount) 558 if (snippets_.size() > kMaxSnippetCount) {
559 to_delete.insert(
560 to_delete.end(),
561 std::make_move_iterator(snippets_.begin() + kMaxSnippetCount),
562 std::make_move_iterator(snippets_.end()));
522 snippets_.resize(kMaxSnippetCount); 563 snippets_.resize(kMaxSnippetCount);
564 }
523 565
524 StoreSnippetsToPrefs(); 566 // Move expired discarded snippets over into |to_delete| as well.
567 for (std::unique_ptr<NTPSnippet>& snippet : discarded_snippets_) {
568 if (snippet->expiry_date() <= expiry)
569 to_delete.emplace_back(std::move(snippet));
570 }
571 Compact(&discarded_snippets_);
525 572
526 discarded_snippets_.erase( 573 // Finally, actually delete the removed snippets from the DB.
527 std::remove_if(discarded_snippets_.begin(), discarded_snippets_.end(), 574 database_->Delete(to_delete);
528 [&expiry](const std::unique_ptr<NTPSnippet>& snippet) {
529 return snippet->expiry_date() <= expiry;
530 }),
531 discarded_snippets_.end());
532 StoreDiscardedSnippetsToPrefs();
533 575
534 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", 576 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
535 snippets_.size()); 577 snippets_.size());
536 if (snippets_.empty() && !discarded_snippets_.empty()) { 578 if (snippets_.empty() && !discarded_snippets_.empty()) {
537 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 579 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
538 discarded_snippets_.size()); 580 discarded_snippets_.size());
539 } 581 }
540 582
541 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 583 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
542 NTPSnippetsServiceLoaded()); 584 NTPSnippetsServiceLoaded());
(...skipping 19 matching lines...) Expand all
562 604
563 bool NTPSnippetsService::IsSyncStateIncompatible() { 605 bool NTPSnippetsService::IsSyncStateIncompatible() {
564 if (!sync_service_ || !sync_service_->CanSyncStart()) 606 if (!sync_service_ || !sync_service_->CanSyncStart())
565 return true; 607 return true;
566 if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) 608 if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone())
567 return false; // Sync service is not initialized, yet not disabled. 609 return false; // Sync service is not initialized, yet not disabled.
568 return !sync_service_->GetActiveDataTypes().Has( 610 return !sync_service_->GetActiveDataTypes().Has(
569 syncer::HISTORY_DELETE_DIRECTIVES); 611 syncer::HISTORY_DELETE_DIRECTIVES);
570 } 612 }
571 613
614 void NTPSnippetsService::ClearDeprecatedPrefs() {
615 pref_service_->ClearPref(prefs::kDeprecatedSnippets);
616 pref_service_->ClearPref(prefs::kDeprecatedDiscardedSnippets);
617 }
618
572 } // namespace ntp_snippets 619 } // namespace ntp_snippets
OLDNEW
« 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