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

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

Powered by Google App Engine
This is Rietveld 408576698