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

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

Powered by Google App Engine
This is Rietveld 408576698