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

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

Powered by Google App Engine
This is Rietveld 408576698